Version Description
- Prevent uncaught exceptions with static method actions
- Misc formatting tweaks
Download this release
Release Info
Developer | johnbillion |
Plugin | Query Monitor |
Version | 2.5.2 |
Comparing to | |
See all releases |
Version 2.5.2
- Backtrace.php +151 -0
- Component.php +68 -0
- Plugin.php +87 -0
- Util.php +247 -0
- assets/query-monitor.css +366 -0
- assets/query-monitor.js +162 -0
- autoloader.php +35 -0
- components/admin.php +172 -0
- components/authentication.php +114 -0
- components/conditionals.php +126 -0
- components/db_callers.php +139 -0
- components/db_components.php +138 -0
- components/db_queries.php +506 -0
- components/environment.php +354 -0
- components/hooks.php +185 -0
- components/http.php +247 -0
- components/overview.php +134 -0
- components/php_errors.php +238 -0
- components/query_vars.php +126 -0
- components/redirects.php +54 -0
- components/theme.php +128 -0
- components/transients.php +144 -0
- composer.json +16 -0
- query-monitor.php +328 -0
- readme.txt +291 -0
- wp-content/db.php +153 -0
Backtrace.php
ADDED
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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_Backtrace {
|
18 |
+
|
19 |
+
protected static $ignore_class = array(
|
20 |
+
'wpdb' => true,
|
21 |
+
'QueryMonitor' => true,
|
22 |
+
'QueryMonitorDB' => true,
|
23 |
+
'ExtQuery' => true,
|
24 |
+
'W3_Db' => true,
|
25 |
+
'Debug_Bar_PHP' => true,
|
26 |
+
);
|
27 |
+
protected static $ignore_method = array();
|
28 |
+
protected static $ignore_func = array(
|
29 |
+
'include_once' => true,
|
30 |
+
'require_once' => true,
|
31 |
+
'include' => true,
|
32 |
+
'require' => true,
|
33 |
+
'call_user_func_array' => true,
|
34 |
+
'call_user_func' => true,
|
35 |
+
'trigger_error' => true,
|
36 |
+
'_doing_it_wrong' => true,
|
37 |
+
'_deprecated_argument' => true,
|
38 |
+
'_deprecated_file' => true,
|
39 |
+
'_deprecated_function' => true,
|
40 |
+
);
|
41 |
+
protected static $show_args = array(
|
42 |
+
'do_action' => 1,
|
43 |
+
'apply_filters' => 1,
|
44 |
+
'do_action_ref_array' => 1,
|
45 |
+
'apply_filters_ref_array' => 1,
|
46 |
+
'get_template_part' => 2,
|
47 |
+
'section_template' => 2,
|
48 |
+
'load_template' => 'dir',
|
49 |
+
'get_header' => 1,
|
50 |
+
'get_sidebar' => 1,
|
51 |
+
'get_footer' => 1,
|
52 |
+
);
|
53 |
+
protected static $filtered = false;
|
54 |
+
|
55 |
+
public function __construct( array $args = array() ) {
|
56 |
+
$args = array_merge( array(
|
57 |
+
'ignore_current_filter' => true,
|
58 |
+
'ignore_items' => 0,
|
59 |
+
), $args );
|
60 |
+
$this->trace = debug_backtrace( false );
|
61 |
+
$this->ignore( 1 ); # Self-awareness
|
62 |
+
|
63 |
+
if ( $args['ignore_items'] )
|
64 |
+
$this->ignore( $args['ignore_items'] );
|
65 |
+
if ( $args['ignore_current_filter'] )
|
66 |
+
$this->ignore_current_filter();
|
67 |
+
|
68 |
+
}
|
69 |
+
|
70 |
+
public function get_stack() {
|
71 |
+
$trace = array_map( 'QM_Backtrace::filter_trace', $this->trace );
|
72 |
+
$trace = array_values( array_filter( $trace ) );
|
73 |
+
return $trace;
|
74 |
+
}
|
75 |
+
|
76 |
+
public function get_trace() {
|
77 |
+
return $this->trace;
|
78 |
+
}
|
79 |
+
|
80 |
+
public function ignore( $num ) {
|
81 |
+
for ( $i = 0; $i < absint( $num ); $i++ )
|
82 |
+
unset( $this->trace[$i] );
|
83 |
+
$this->trace = array_values( $this->trace );
|
84 |
+
return $this;
|
85 |
+
}
|
86 |
+
|
87 |
+
public function ignore_current_filter() {
|
88 |
+
|
89 |
+
if ( isset( $this->trace[2] ) and isset( $this->trace[2]['function'] ) ) {
|
90 |
+
if ( in_array( $this->trace[2]['function'], array( 'apply_filters', 'do_action' ) ) )
|
91 |
+
$this->ignore( 3 ); # Ignore filter and action callbacks
|
92 |
+
}
|
93 |
+
|
94 |
+
}
|
95 |
+
|
96 |
+
public static function filter_trace( array $trace ) {
|
97 |
+
|
98 |
+
if ( !self::$filtered and function_exists( 'did_action' ) and did_action( 'plugins_loaded' ) ) {
|
99 |
+
|
100 |
+
# Only run apply_filters on these once
|
101 |
+
self::$ignore_class = apply_filters( 'query_monitor_ignore_class', self::$ignore_class );
|
102 |
+
self::$ignore_method = apply_filters( 'query_monitor_ignore_method', self::$ignore_method );
|
103 |
+
self::$ignore_func = apply_filters( 'query_monitor_ignore_func', self::$ignore_func );
|
104 |
+
self::$show_args = apply_filters( 'query_monitor_show_args', self::$show_args );
|
105 |
+
self::$filtered = true;
|
106 |
+
|
107 |
+
}
|
108 |
+
|
109 |
+
if ( isset( $trace['class'] ) ) {
|
110 |
+
|
111 |
+
if ( isset( self::$ignore_class[$trace['class']] ) )
|
112 |
+
return null;
|
113 |
+
else if ( isset( self::$ignore_method[$trace['class']][$trace['function']] ) )
|
114 |
+
return null;
|
115 |
+
else if ( 0 === strpos( $trace['class'], 'QM_' ) )
|
116 |
+
return null;
|
117 |
+
else
|
118 |
+
return $trace['class'] . $trace['type'] . $trace['function'] . '()';
|
119 |
+
|
120 |
+
} else {
|
121 |
+
|
122 |
+
if ( isset( self::$ignore_func[$trace['function']] ) ) {
|
123 |
+
|
124 |
+
return null;
|
125 |
+
|
126 |
+
} else if ( isset( self::$show_args[$trace['function']] ) ) {
|
127 |
+
|
128 |
+
$show = self::$show_args[$trace['function']];
|
129 |
+
if ( 'dir' === $show ) {
|
130 |
+
if ( isset( $trace['args'][0] ) ) {
|
131 |
+
$arg = QM_Util::standard_dir( $trace['args'][0], '…/' );
|
132 |
+
return $trace['function'] . "('{$arg}')";
|
133 |
+
}
|
134 |
+
} else {
|
135 |
+
$args = array();
|
136 |
+
for ( $i = 0; $i < $show; $i++ ) {
|
137 |
+
if ( isset( $trace['args'][$i] ) )
|
138 |
+
$args[] = sprintf( "'%s'", $trace['args'][$i] );
|
139 |
+
}
|
140 |
+
return $trace['function'] . '(' . implode( ',', $args ) . ')';
|
141 |
+
}
|
142 |
+
|
143 |
+
}
|
144 |
+
|
145 |
+
return $trace['function'] . '()';
|
146 |
+
|
147 |
+
}
|
148 |
+
|
149 |
+
}
|
150 |
+
|
151 |
+
}
|
Component.php
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
abstract class QM_Component {
|
18 |
+
|
19 |
+
protected $data = array();
|
20 |
+
|
21 |
+
protected function __construct() {}
|
22 |
+
|
23 |
+
final public function id() {
|
24 |
+
return "qm-{$this->id}";
|
25 |
+
}
|
26 |
+
|
27 |
+
final protected function menu( array $args ) {
|
28 |
+
|
29 |
+
return wp_parse_args( $args, array(
|
30 |
+
'id' => "query-monitor-{$this->id}",
|
31 |
+
'href' => '#' . $this->id()
|
32 |
+
) );
|
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 ) {
|
43 |
+
|
44 |
+
usort( $values, 'strcasecmp' );
|
45 |
+
|
46 |
+
$out = '<select id="qm-filter-' . esc_attr( $this->id . '-' . $name ) . '" class="qm-filter" data-filter="' . esc_attr( $this->id . '-' . $name ) . '">';
|
47 |
+
$out .= '<option value="">' . _x( 'All', '"All" option for filters', 'query-monitor' ) . '</option>';
|
48 |
+
|
49 |
+
foreach ( $values as $value )
|
50 |
+
$out .= '<option value="' . esc_attr( $value ) . '">' . esc_html( $value ) . '</option>';
|
51 |
+
|
52 |
+
$out .= '</select>';
|
53 |
+
|
54 |
+
return $out;
|
55 |
+
|
56 |
+
}
|
57 |
+
|
58 |
+
final public function get_data() {
|
59 |
+
return $this->data;
|
60 |
+
}
|
61 |
+
|
62 |
+
public function process() {}
|
63 |
+
|
64 |
+
public function output_html( array $args, array $data ) {}
|
65 |
+
|
66 |
+
public function output_headers( array $args, array $data ) {}
|
67 |
+
|
68 |
+
}
|
Plugin.php
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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_Plugin {
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Class constructor
|
21 |
+
*
|
22 |
+
* @author John Blackbourn
|
23 |
+
**/
|
24 |
+
public function __construct( $file ) {
|
25 |
+
$this->file = $file;
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Returns the URL for for a file/dir within this plugin.
|
30 |
+
*
|
31 |
+
* @param $file string The path within this plugin, e.g. '/js/clever-fx.js'
|
32 |
+
* @return string URL
|
33 |
+
* @author John Blackbourn
|
34 |
+
**/
|
35 |
+
final public function plugin_url( $file = '' ) {
|
36 |
+
return $this->_plugin( 'url', $file );
|
37 |
+
}
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Returns the filesystem path for a file/dir within this plugin.
|
41 |
+
*
|
42 |
+
* @param $file string The path within this plugin, e.g. '/js/clever-fx.js'
|
43 |
+
* @return string Filesystem path
|
44 |
+
* @author John Blackbourn
|
45 |
+
**/
|
46 |
+
final public function plugin_path( $file = '' ) {
|
47 |
+
return $this->_plugin( 'path', $file );
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Returns a version number for the given plugin file.
|
52 |
+
*
|
53 |
+
* @param $file string The path within this plugin, e.g. '/js/clever-fx.js'
|
54 |
+
* @return string Version
|
55 |
+
* @author John Blackbourn
|
56 |
+
**/
|
57 |
+
final public function plugin_ver( $file ) {
|
58 |
+
return filemtime( $this->plugin_path( $file ) );
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Returns the current plugin's basename, eg. 'my_plugin/my_plugin.php'.
|
63 |
+
*
|
64 |
+
* @return string Basename
|
65 |
+
* @author John Blackbourn
|
66 |
+
**/
|
67 |
+
final public function plugin_base() {
|
68 |
+
return $this->_plugin( 'base' );
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Populates and returns the current plugin info.
|
73 |
+
*
|
74 |
+
* @author John Blackbourn
|
75 |
+
**/
|
76 |
+
final protected function _plugin( $item, $file = '' ) {
|
77 |
+
if ( !isset( $this->plugin ) ) {
|
78 |
+
$this->plugin = array(
|
79 |
+
'url' => plugin_dir_url( $this->file ),
|
80 |
+
'path' => plugin_dir_path( $this->file ),
|
81 |
+
'base' => plugin_basename( $this->file )
|
82 |
+
);
|
83 |
+
}
|
84 |
+
return $this->plugin[$item] . ltrim( $file, '/' );
|
85 |
+
}
|
86 |
+
|
87 |
+
}
|
Util.php
ADDED
@@ -0,0 +1,247 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
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_Util {
|
19 |
+
|
20 |
+
protected static $file_components = array();
|
21 |
+
protected static $file_dirs = array();
|
22 |
+
|
23 |
+
private function __construct() {}
|
24 |
+
|
25 |
+
public static function timer_stop_float() {
|
26 |
+
global $timestart;
|
27 |
+
return microtime( true ) - $timestart;
|
28 |
+
}
|
29 |
+
|
30 |
+
public static function sort( $a, $b ) {
|
31 |
+
if ( $a['ltime'] == $b['ltime'] )
|
32 |
+
return 0;
|
33 |
+
else
|
34 |
+
return ( $a['ltime'] > $b['ltime'] ) ? -1 : 1;
|
35 |
+
}
|
36 |
+
|
37 |
+
public static function convert_hr_to_bytes( $size ) {
|
38 |
+
|
39 |
+
# Annoyingly, wp_convert_hr_to_bytes() is defined in a file that's only
|
40 |
+
# loaded in the admin area, so we'll use our own version.
|
41 |
+
# See also http://core.trac.wordpress.org/ticket/17725
|
42 |
+
|
43 |
+
$bytes = (float) $size;
|
44 |
+
|
45 |
+
if ( $bytes ) {
|
46 |
+
$last = strtolower( substr( $size, -1 ) );
|
47 |
+
$pos = strpos( ' kmg', $last, 1);
|
48 |
+
if ( $pos )
|
49 |
+
$bytes *= pow( 1024, $pos );
|
50 |
+
$bytes = round( $bytes );
|
51 |
+
}
|
52 |
+
|
53 |
+
return $bytes;
|
54 |
+
|
55 |
+
}
|
56 |
+
|
57 |
+
public static function standard_dir( $dir, $abspath_replace = null ) {
|
58 |
+
|
59 |
+
$dir = str_replace( '\\', '/', $dir );
|
60 |
+
$dir = preg_replace( '|/+|', '/', $dir );
|
61 |
+
|
62 |
+
if ( is_string( $abspath_replace ) )
|
63 |
+
$dir = str_replace( self::standard_dir( ABSPATH ), $abspath_replace, $dir );
|
64 |
+
|
65 |
+
return $dir;
|
66 |
+
|
67 |
+
}
|
68 |
+
|
69 |
+
public static function get_file_component( $file ) {
|
70 |
+
|
71 |
+
# @TODO turn this into a class (eg QM_File_Component)
|
72 |
+
|
73 |
+
if ( isset( self::$file_components[$file] ) )
|
74 |
+
return self::$file_components[$file];
|
75 |
+
|
76 |
+
if ( empty( self::$file_dirs ) ) {
|
77 |
+
self::$file_dirs['plugin'] = self::standard_dir( WP_PLUGIN_DIR );
|
78 |
+
self::$file_dirs['muplugin'] = self::standard_dir( WPMU_PLUGIN_DIR );
|
79 |
+
self::$file_dirs['stylesheet'] = self::standard_dir( get_stylesheet_directory() );
|
80 |
+
self::$file_dirs['template'] = self::standard_dir( get_template_directory() );
|
81 |
+
self::$file_dirs['other'] = self::standard_dir( WP_CONTENT_DIR );
|
82 |
+
self::$file_dirs['core'] = self::standard_dir( ABSPATH );
|
83 |
+
}
|
84 |
+
|
85 |
+
foreach ( self::$file_dirs as $type => $dir ) {
|
86 |
+
if ( 0 === strpos( $file, $dir ) )
|
87 |
+
break;
|
88 |
+
}
|
89 |
+
|
90 |
+
switch ( $type ) {
|
91 |
+
case 'plugin':
|
92 |
+
case 'muplugin':
|
93 |
+
$plug = plugin_basename( $file );
|
94 |
+
if ( strpos( $plug, '/' ) ) {
|
95 |
+
$plug = explode( '/', $plug );
|
96 |
+
$plug = reset( $plug );
|
97 |
+
} else {
|
98 |
+
$plug = basename( $plug );
|
99 |
+
}
|
100 |
+
$name = sprintf( __( 'Plugin: %s', 'query-monitor' ), $plug );
|
101 |
+
break;
|
102 |
+
case 'stylesheet':
|
103 |
+
$name = __( 'Theme', 'query-monitor' );
|
104 |
+
break;
|
105 |
+
case 'template':
|
106 |
+
$name = __( 'Parent Theme', 'query-monitor' );
|
107 |
+
break;
|
108 |
+
case 'other':
|
109 |
+
$name = self::standard_dir( $file, '' );
|
110 |
+
break;
|
111 |
+
case 'core':
|
112 |
+
default:
|
113 |
+
$name = __( 'Core', 'query-monitor' );
|
114 |
+
break;
|
115 |
+
}
|
116 |
+
|
117 |
+
return self::$file_components[$file] = (object) compact( 'type', 'name' );
|
118 |
+
|
119 |
+
}
|
120 |
+
|
121 |
+
public static function get_backtrace_component( QM_Backtrace $backtrace ) {
|
122 |
+
|
123 |
+
# @TODO turn this into a class (eg QM_Trace_Component)
|
124 |
+
|
125 |
+
$components = array();
|
126 |
+
|
127 |
+
foreach ( $backtrace->get_trace() as $item ) {
|
128 |
+
|
129 |
+
try {
|
130 |
+
|
131 |
+
if ( isset( $item['file'] ) ) {
|
132 |
+
$file = $item['file'];
|
133 |
+
} else if ( isset( $item['class'] ) ) {
|
134 |
+
$ref = new ReflectionMethod( $item['class'], $item['function'] );
|
135 |
+
$file = $ref->getFileName();
|
136 |
+
} else {
|
137 |
+
$ref = new ReflectionFunction( $item['function'] );
|
138 |
+
$file = $ref->getFileName();
|
139 |
+
}
|
140 |
+
|
141 |
+
$comp = self::get_file_component( $file );
|
142 |
+
$components[$comp->type] = $comp;
|
143 |
+
} catch ( ReflectionException $e ) {
|
144 |
+
# nothing
|
145 |
+
}
|
146 |
+
|
147 |
+
}
|
148 |
+
|
149 |
+
foreach ( self::$file_dirs as $type => $dir ) {
|
150 |
+
if ( isset( $components[$type] ) )
|
151 |
+
return $components[$type];
|
152 |
+
}
|
153 |
+
|
154 |
+
# This should not happen
|
155 |
+
|
156 |
+
}
|
157 |
+
|
158 |
+
public static function populate_callback( array $callback ) {
|
159 |
+
|
160 |
+
$access = '->';
|
161 |
+
|
162 |
+
if ( is_string( $callback['function'] ) and ( false !== strpos( $callback['function'], '::' ) ) ) {
|
163 |
+
$callback['function'] = explode( '::', $callback['function'] );
|
164 |
+
$access = '::';
|
165 |
+
}
|
166 |
+
|
167 |
+
try {
|
168 |
+
|
169 |
+
if ( is_array( $callback['function'] ) ) {
|
170 |
+
|
171 |
+
if ( is_object( $callback['function'][0] ) )
|
172 |
+
$class = get_class( $callback['function'][0] );
|
173 |
+
else
|
174 |
+
$class = $callback['function'][0];
|
175 |
+
|
176 |
+
$callback['name'] = $class . $access . $callback['function'][1] . '()';
|
177 |
+
$ref = new ReflectionMethod( $class, $callback['function'][1] );
|
178 |
+
|
179 |
+
} else if ( is_object( $callback['function'] ) and is_a( $callback['function'], 'Closure' ) ) {
|
180 |
+
|
181 |
+
$ref = new ReflectionFunction( $callback['function'] );
|
182 |
+
$file = trim( QM_Util::standard_dir( $ref->getFileName(), '' ), '/' );
|
183 |
+
$callback['name'] = sprintf( __( '{closure}() on line %1$d of %2$s', 'query-monitor' ), $ref->getEndLine(), $file );
|
184 |
+
|
185 |
+
} else {
|
186 |
+
|
187 |
+
$callback['name'] = $callback['function'] . '()';
|
188 |
+
$ref = new ReflectionFunction( $callback['function'] );
|
189 |
+
|
190 |
+
}
|
191 |
+
|
192 |
+
$callback['component'] = self::get_file_component( $ref->getFileName() );
|
193 |
+
|
194 |
+
} catch ( ReflectionException $e ) {
|
195 |
+
|
196 |
+
# Nothing
|
197 |
+
|
198 |
+
}
|
199 |
+
|
200 |
+
return $callback;
|
201 |
+
|
202 |
+
}
|
203 |
+
|
204 |
+
public static function is_ajax() {
|
205 |
+
if ( defined( 'DOING_AJAX' ) and DOING_AJAX )
|
206 |
+
return true;
|
207 |
+
if ( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) and 'xmlhttprequest' == strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) )
|
208 |
+
return true;
|
209 |
+
return false;
|
210 |
+
}
|
211 |
+
|
212 |
+
public static function wpv() {
|
213 |
+
return 'qm-wp-' . ( floatval( $GLOBALS['wp_version'] ) * 10 );
|
214 |
+
}
|
215 |
+
|
216 |
+
public static function get_admins() {
|
217 |
+
if ( is_multisite() )
|
218 |
+
return false;
|
219 |
+
else
|
220 |
+
return get_role( 'administrator' );
|
221 |
+
}
|
222 |
+
|
223 |
+
public static function format_sql( $sql ) {
|
224 |
+
|
225 |
+
$sql = str_replace( array( "\r\n", "\r", "\n", "\t" ), ' ', $sql );
|
226 |
+
$sql = esc_html( $sql );
|
227 |
+
$sql = trim( $sql );
|
228 |
+
|
229 |
+
foreach( array(
|
230 |
+
'ALTER', 'AND', 'COMMIT', 'CREATE', 'DESCRIBE', 'DELETE', 'DROP', 'ELSE', 'END', 'FROM', 'GROUP',
|
231 |
+
'HAVING', 'INNER', 'INSERT', 'LIMIT', 'ON', 'OR', 'ORDER', 'REPLACE', 'ROLLBACK', 'SELECT', 'SET',
|
232 |
+
'SHOW', 'START', 'THEN', 'TRUNCATE', 'UPDATE', 'VALUES', 'WHEN', 'WHERE'
|
233 |
+
) as $cmd )
|
234 |
+
$sql = trim( str_replace( " $cmd ", "<br/>$cmd ", $sql ) );
|
235 |
+
|
236 |
+
return $sql;
|
237 |
+
|
238 |
+
}
|
239 |
+
|
240 |
+
public static function format_bool_constant( $constant ) {
|
241 |
+
if ( !defined( $constant ) or !constant( $constant ) )
|
242 |
+
return 'false';
|
243 |
+
else
|
244 |
+
return 'true';
|
245 |
+
}
|
246 |
+
|
247 |
+
}
|
assets/query-monitor.css
ADDED
@@ -0,0 +1,366 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
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 |
+
|
18 |
+
#wpadminbar .quicklinks .menupop ul li.qm-true > a {
|
19 |
+
color: #4a4 !important;
|
20 |
+
}
|
21 |
+
body.mp6 #wpadminbar .quicklinks .menupop ul li.qm-true > a {
|
22 |
+
color: #8c8 !important;
|
23 |
+
}
|
24 |
+
body.mp6 #wpadminbar .quicklinks .menupop ul li.qm-true > a:hover {
|
25 |
+
color: #4a4 !important;
|
26 |
+
}
|
27 |
+
|
28 |
+
#wp-admin-bar-query-monitor-notices {
|
29 |
+
background-color: #740 !important;
|
30 |
+
}
|
31 |
+
|
32 |
+
#wpadminbar .qm-notice {
|
33 |
+
background-color: #740;
|
34 |
+
}
|
35 |
+
|
36 |
+
#wp-admin-bar-query-monitor-stricts {
|
37 |
+
background-color: #eee !important;
|
38 |
+
}
|
39 |
+
|
40 |
+
#wpadminbar .qm-strict {
|
41 |
+
background-color: #000;
|
42 |
+
}
|
43 |
+
|
44 |
+
#wp-admin-bar-query-monitor-expensive {
|
45 |
+
background-color: #b60 !important;
|
46 |
+
}
|
47 |
+
|
48 |
+
#wpadminbar .qm-expensive {
|
49 |
+
background-color: #b60;
|
50 |
+
}
|
51 |
+
|
52 |
+
#wp-admin-bar-query-monitor-warnings {
|
53 |
+
background-color: #c00 !important;
|
54 |
+
}
|
55 |
+
|
56 |
+
#wpadminbar .qm-warning {
|
57 |
+
background-color: #c00;
|
58 |
+
}
|
59 |
+
|
60 |
+
#wp-admin-bar-query-monitor-errors {
|
61 |
+
background-color: #c00 !important;
|
62 |
+
}
|
63 |
+
|
64 |
+
#wpadminbar .qm-error {
|
65 |
+
background-color: #c00 !important;
|
66 |
+
}
|
67 |
+
|
68 |
+
#wp-admin-bar-query-monitor-stricts a {
|
69 |
+
color: #555 !important;
|
70 |
+
}
|
71 |
+
|
72 |
+
#wp-admin-bar-query-monitor-notices a,
|
73 |
+
#wp-admin-bar-query-monitor-expensive a,
|
74 |
+
#wp-admin-bar-query-monitor-warnings a,
|
75 |
+
#wp-admin-bar-query-monitor-errors a {
|
76 |
+
color: #eee !important;
|
77 |
+
}
|
78 |
+
|
79 |
+
#wp-admin-bar-query-monitor small {
|
80 |
+
font-size: 11px !important;
|
81 |
+
}
|
82 |
+
|
83 |
+
#wp-admin-bar-query-monitor.hover a small,
|
84 |
+
#wp-admin-bar-query-monitor.hover a .ab-label {
|
85 |
+
text-shadow: none !important;
|
86 |
+
color: #333 !important;
|
87 |
+
}
|
88 |
+
body.mp6 #wp-admin-bar-query-monitor.hover a small,
|
89 |
+
body.mp6 #wp-admin-bar-query-monitor.hover a .ab-label {
|
90 |
+
color: #2ea2cc !important;
|
91 |
+
}
|
92 |
+
|
93 |
+
#wp-admin-bar-query-monitor-placeholder,
|
94 |
+
#wp-admin-bar-query-monitor-default {
|
95 |
+
display: none;
|
96 |
+
}
|
97 |
+
|
98 |
+
#wpadminbar #wp-admin-bar-query-monitor .ab-icon {
|
99 |
+
font: 16px/16px 'Open Sans', sans-serif !important;
|
100 |
+
width: auto !important;
|
101 |
+
padding: 0 2px !important;
|
102 |
+
color: #999 !important;
|
103 |
+
line-height: 32px !important;
|
104 |
+
display: none !important;
|
105 |
+
}
|
106 |
+
|
107 |
+
@media screen and (max-width: 782px) {
|
108 |
+
body.mp6 #wpadminbar #wp-admin-bar-query-monitor .ab-icon {
|
109 |
+
display: block !important;
|
110 |
+
}
|
111 |
+
}
|
112 |
+
|
113 |
+
#qm {
|
114 |
+
clear: both !important;
|
115 |
+
background: #eeeeee !important;
|
116 |
+
margin: 25px 0 0 !important;
|
117 |
+
border-top: 1px solid #ccc !important;
|
118 |
+
padding: 0 0 35px !important;
|
119 |
+
text-align: left !important;
|
120 |
+
display: none;
|
121 |
+
}
|
122 |
+
|
123 |
+
#qm.qm-show,
|
124 |
+
.no-js #qm,
|
125 |
+
.nojs #qm {
|
126 |
+
display: block;
|
127 |
+
}
|
128 |
+
|
129 |
+
#qm:after {
|
130 |
+
display: block !important;
|
131 |
+
content: '' !important;
|
132 |
+
clear: both !important;
|
133 |
+
height: 0 !important;
|
134 |
+
}
|
135 |
+
|
136 |
+
body.wp-admin #qm {
|
137 |
+
margin: 0 !important;
|
138 |
+
}
|
139 |
+
|
140 |
+
body.sticky-menu #qm {
|
141 |
+
margin-left: 150px !important;
|
142 |
+
}
|
143 |
+
|
144 |
+
body.sticky-menu.folded #qm {
|
145 |
+
margin-left: 36px !important;
|
146 |
+
}
|
147 |
+
|
148 |
+
#qm-wrapper {
|
149 |
+
margin: 0 auto;
|
150 |
+
max-width: 85em;
|
151 |
+
}
|
152 |
+
|
153 |
+
#qm-wrapper > p {
|
154 |
+
color: #777 !important;
|
155 |
+
font: 13px/15px 'Open Sans', Arial !important;
|
156 |
+
margin: 20px 1% -15px !important;
|
157 |
+
font-style: italic !important;
|
158 |
+
}
|
159 |
+
|
160 |
+
.qm {
|
161 |
+
margin: 0 1% !important;
|
162 |
+
padding: 40px 0 0 !important;
|
163 |
+
clear: both !important;
|
164 |
+
}
|
165 |
+
|
166 |
+
.qm-half {
|
167 |
+
float: left !important;
|
168 |
+
width: 48% !important;
|
169 |
+
clear: none !important;
|
170 |
+
}
|
171 |
+
|
172 |
+
.qm>table {
|
173 |
+
border-collapse: collapse !important;
|
174 |
+
color: #555 !important;
|
175 |
+
border-style: hidden !important;
|
176 |
+
box-shadow: 0 1px 1px -1px rgba(0,0,0,0.1) !important;
|
177 |
+
width: 100% !important;
|
178 |
+
border: 1px solid #dedede !important;
|
179 |
+
}
|
180 |
+
|
181 |
+
.qm td,
|
182 |
+
.qm th {
|
183 |
+
background: #fff !important;
|
184 |
+
text-align: left !important;
|
185 |
+
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace !important;
|
186 |
+
font-size: 11px !important;
|
187 |
+
font-weight: normal !important;
|
188 |
+
font-style: normal !important;
|
189 |
+
line-height: 16px !important;
|
190 |
+
border: 1px solid #e1e1e1 !important;
|
191 |
+
padding: 5px 8px 4px !important;
|
192 |
+
vertical-align: top !important;
|
193 |
+
text-shadow: none !important;
|
194 |
+
text-transform: none !important;
|
195 |
+
}
|
196 |
+
|
197 |
+
.qm tbody tr:hover th,
|
198 |
+
.qm tbody tr:hover td {
|
199 |
+
background: #f5f5f5 !important;
|
200 |
+
}
|
201 |
+
|
202 |
+
#qm-conditionals tbody tr:hover td,
|
203 |
+
#qm-overview tbody tr:hover td,
|
204 |
+
#qm-authentication tbody tr:hover td,
|
205 |
+
.qm tbody tr:hover th[rowspan],
|
206 |
+
.qm tbody tr:hover td[rowspan] {
|
207 |
+
background: #fff !important;
|
208 |
+
}
|
209 |
+
|
210 |
+
.qm th {
|
211 |
+
color: #444 !important;
|
212 |
+
}
|
213 |
+
|
214 |
+
.qm-inner {
|
215 |
+
border-collapse: collapse !important;
|
216 |
+
margin: 0 !important;
|
217 |
+
background: #fff !important;
|
218 |
+
color: #555 !important;
|
219 |
+
border: none !important;
|
220 |
+
}
|
221 |
+
|
222 |
+
.qm-inner td,
|
223 |
+
.qm-inner th {
|
224 |
+
text-align: left !important;
|
225 |
+
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace !important;
|
226 |
+
font-size: 11px !important;
|
227 |
+
line-height: 16px !important;
|
228 |
+
border: none !important;
|
229 |
+
padding: 1px 0 !important;
|
230 |
+
}
|
231 |
+
|
232 |
+
.qm ul {
|
233 |
+
margin: 0 !important;
|
234 |
+
padding: 0 0 0 10px !important;
|
235 |
+
list-style: none !important;
|
236 |
+
}
|
237 |
+
|
238 |
+
.qm li {
|
239 |
+
margin-bottom: 2px !important;
|
240 |
+
}
|
241 |
+
|
242 |
+
.qm span.qm-true,
|
243 |
+
.qm td.qm-true {
|
244 |
+
color: #4a4 !important;
|
245 |
+
}
|
246 |
+
|
247 |
+
.qm span.qm-false,
|
248 |
+
.qm td.qm-false {
|
249 |
+
color: #ccc !important;
|
250 |
+
}
|
251 |
+
|
252 |
+
.qm span.qm-na,
|
253 |
+
.qm tr.qm-na {
|
254 |
+
color: #ccc !important;
|
255 |
+
}
|
256 |
+
|
257 |
+
.qm .qm-sql {
|
258 |
+
word-wrap: break-word !important;
|
259 |
+
word-break: break-all !important;
|
260 |
+
}
|
261 |
+
|
262 |
+
.qm .qm-nonselectsql {
|
263 |
+
color: #a0a !important;
|
264 |
+
}
|
265 |
+
|
266 |
+
.qm .qm-current {
|
267 |
+
color: #a0a !important;
|
268 |
+
}
|
269 |
+
|
270 |
+
.qm .qm-url span {
|
271 |
+
color: #ccc !important;
|
272 |
+
}
|
273 |
+
|
274 |
+
.qm .qm-info {
|
275 |
+
color: #999 !important;
|
276 |
+
}
|
277 |
+
|
278 |
+
.qm a {
|
279 |
+
color: #0074a2 !important;
|
280 |
+
text-decoration: none !important;
|
281 |
+
text-shadow: none !important;
|
282 |
+
font-weight: normal !important;
|
283 |
+
}
|
284 |
+
.qm a:hover {
|
285 |
+
text-decoration: underline !important;
|
286 |
+
color: #2ea2cc !important;
|
287 |
+
}
|
288 |
+
|
289 |
+
.qm a.qm-warn {
|
290 |
+
text-decoration: underline !important;
|
291 |
+
}
|
292 |
+
|
293 |
+
.qm .qm-warn,
|
294 |
+
.qm .qm-warn span.qm-na {
|
295 |
+
color: #f00 !important;
|
296 |
+
}
|
297 |
+
|
298 |
+
.qm span.qm-expensive,
|
299 |
+
.qm td.qm-expensive {
|
300 |
+
color: #f44 !important;
|
301 |
+
}
|
302 |
+
|
303 |
+
.qm td.qm-priority {
|
304 |
+
text-align: right !important;
|
305 |
+
}
|
306 |
+
|
307 |
+
.qm td.qm-var {
|
308 |
+
text-align: right !important;
|
309 |
+
padding: 1px 1.5em 1px 0 !important;
|
310 |
+
}
|
311 |
+
|
312 |
+
.qm-param {
|
313 |
+
padding: 0 6px !important;
|
314 |
+
}
|
315 |
+
|
316 |
+
/* Filters */
|
317 |
+
|
318 |
+
select.qm-filter {
|
319 |
+
display: block !important;
|
320 |
+
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace !important;
|
321 |
+
font-weight: normal !important;
|
322 |
+
font-size: 11px !important;
|
323 |
+
margin: 4px 0 2px !important;
|
324 |
+
border: 1px solid #e6e6e6 !important;
|
325 |
+
padding: 1px !important;
|
326 |
+
background: #fff !important;
|
327 |
+
color: #444 !important;
|
328 |
+
height: 2em !important;
|
329 |
+
width: auto !important;
|
330 |
+
border-radius: 0 !important;
|
331 |
+
float: none !important;
|
332 |
+
cursor: pointer !important;
|
333 |
+
text-transform: none !important;
|
334 |
+
-webkit-appearance: menulist !important;
|
335 |
+
-moz-appearance: menulist !important;
|
336 |
+
}
|
337 |
+
|
338 |
+
.qm-hide,
|
339 |
+
.qm-hide-hooks-component,
|
340 |
+
.qm-hide-hooks-name,
|
341 |
+
.qm-hide-db_queries-type,
|
342 |
+
.qm-hide-db_queries-caller,
|
343 |
+
.qm-hide-db_queries-component {
|
344 |
+
display: none !important;
|
345 |
+
}
|
346 |
+
|
347 |
+
/* RTL */
|
348 |
+
|
349 |
+
html[dir="rtl"] .qm-ltr {
|
350 |
+
direction: ltr !important;
|
351 |
+
text-align: right !important;
|
352 |
+
}
|
353 |
+
|
354 |
+
html[dir="rtl"] .qm td.qm-priority {
|
355 |
+
padding: 1px 0 1px 0.75em !important;
|
356 |
+
}
|
357 |
+
|
358 |
+
html[dir="rtl"] .qm td.qm-var {
|
359 |
+
padding: 1px 0 1px 1.5em !important;
|
360 |
+
text-align: left !important;
|
361 |
+
}
|
362 |
+
|
363 |
+
html[dir="rtl"] body.sticky-menu #qm {
|
364 |
+
margin-right: 150px !important;
|
365 |
+
margin-left: 0 !important;
|
366 |
+
}
|
assets/query-monitor.js
ADDED
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
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 |
+
var QM_i18n = {
|
18 |
+
|
19 |
+
// http://core.trac.wordpress.org/ticket/20491
|
20 |
+
|
21 |
+
number_format : function( number, decimals ) {
|
22 |
+
|
23 |
+
if ( isNaN( number ) )
|
24 |
+
return;
|
25 |
+
|
26 |
+
if ( !decimals )
|
27 |
+
decimals = 0;
|
28 |
+
|
29 |
+
number = parseFloat( number );
|
30 |
+
|
31 |
+
var num_float = number.toFixed( decimals ),
|
32 |
+
num_int = Math.floor( number ),
|
33 |
+
num_str = num_int.toString(),
|
34 |
+
fraction = num_float.substring( num_float.indexOf( '.' ) + 1, num_float.length ),
|
35 |
+
o = '';
|
36 |
+
|
37 |
+
if ( num_str.length > 3 ) {
|
38 |
+
for ( i = num_str.length; i > 3; i -= 3 )
|
39 |
+
o = qm_locale.number_format.thousands_sep + num_str.slice( i - 3, i ) + o;
|
40 |
+
o = num_str.slice( 0, i ) + o;
|
41 |
+
} else {
|
42 |
+
o = num_str;
|
43 |
+
}
|
44 |
+
|
45 |
+
if ( decimals )
|
46 |
+
o = o + qm_locale.number_format.decimal_point + fraction;
|
47 |
+
|
48 |
+
return o;
|
49 |
+
|
50 |
+
}
|
51 |
+
|
52 |
+
};
|
53 |
+
|
54 |
+
jQuery( function($) {
|
55 |
+
|
56 |
+
if ( !window.qm )
|
57 |
+
return;
|
58 |
+
|
59 |
+
if ( $('#wp-admin-bar-query-monitor').length ) {
|
60 |
+
|
61 |
+
var container = document.createDocumentFragment();
|
62 |
+
|
63 |
+
$('#wp-admin-bar-query-monitor')
|
64 |
+
.addClass(qm.menu.top.classname)
|
65 |
+
.find('a').eq(0)
|
66 |
+
.html(qm.menu.top.title)
|
67 |
+
;
|
68 |
+
|
69 |
+
$.each( qm.menu.sub, function( i, el ) {
|
70 |
+
|
71 |
+
var new_menu = $('#wp-admin-bar-query-monitor-placeholder')
|
72 |
+
.clone()
|
73 |
+
.attr('id','wp-admin-bar-'+el.id)
|
74 |
+
;
|
75 |
+
new_menu
|
76 |
+
.find('a').eq(0)
|
77 |
+
.html(el.title)
|
78 |
+
.attr('href',el.href)
|
79 |
+
;
|
80 |
+
|
81 |
+
if ( ( typeof el.meta != 'undefined' ) && ( typeof el.meta.classname != 'undefined' ) )
|
82 |
+
new_menu.addClass(el.meta.classname);
|
83 |
+
|
84 |
+
container.appendChild( new_menu.get(0) );
|
85 |
+
|
86 |
+
} );
|
87 |
+
|
88 |
+
$('#wp-admin-bar-query-monitor ul').append(container);
|
89 |
+
|
90 |
+
$('#wp-admin-bar-query-monitor').find('a').on('click',function(e){
|
91 |
+
$('#qm').show();
|
92 |
+
});
|
93 |
+
|
94 |
+
$('#wp-admin-bar-query-monitor,#wp-admin-bar-query-monitor-default').show();
|
95 |
+
|
96 |
+
}
|
97 |
+
|
98 |
+
$('#qm').find('select.qm-filter').on('change',function(e){
|
99 |
+
|
100 |
+
var filter = $(this).attr('data-filter'),
|
101 |
+
table = $(this).closest('table'),
|
102 |
+
tr = table.find('tbody tr[data-qm-' + filter + ']'),
|
103 |
+
val = $(this).val().replace(/[[\]()'"]/g, "\\$&"),
|
104 |
+
total = tr.removeClass('qm-hide-' + filter).length,
|
105 |
+
time = 0;
|
106 |
+
|
107 |
+
if ( $(this).val() !== '' )
|
108 |
+
tr.not('[data-qm-' + filter + '*="' + val + '"]').addClass('qm-hide-' + filter);
|
109 |
+
|
110 |
+
var matches = tr.filter(':visible');
|
111 |
+
matches.each(function(i){
|
112 |
+
var row_time = $(this).attr('data-qm-time');
|
113 |
+
if ( row_time )
|
114 |
+
time += parseFloat( row_time );
|
115 |
+
});
|
116 |
+
if ( time )
|
117 |
+
time = QM_i18n.number_format( time, 4 );
|
118 |
+
|
119 |
+
var results = table.find('.qm-items-shown').removeClass('qm-hide');
|
120 |
+
results.find('.qm-items-number').text(matches.length);
|
121 |
+
results.find('.qm-items-time').text(time);
|
122 |
+
|
123 |
+
$(this).blur();
|
124 |
+
|
125 |
+
});
|
126 |
+
|
127 |
+
$( document ).ajaxSuccess( function( event, response, options ) {
|
128 |
+
|
129 |
+
var errors = response.getResponseHeader( 'X-QM-Errors' );
|
130 |
+
|
131 |
+
if ( !errors )
|
132 |
+
return event;
|
133 |
+
|
134 |
+
errors = $.parseJSON( errors );
|
135 |
+
|
136 |
+
for ( var key in errors ) {
|
137 |
+
|
138 |
+
error = $.parseJSON( response.getResponseHeader( 'X-QM-Error-' + errors[key] ) );
|
139 |
+
|
140 |
+
if ( window.console ) {
|
141 |
+
console.debug( '=== PHP Error in AJAX Response ===' ); // @TODO i18n
|
142 |
+
console.debug( error );
|
143 |
+
}
|
144 |
+
|
145 |
+
if ( $('#wp-admin-bar-query-monitor').length ) {
|
146 |
+
if ( ! qm.ajax_errors[error.type] ) {
|
147 |
+
$('#wp-admin-bar-query-monitor')
|
148 |
+
.addClass('qm-'+error.type)
|
149 |
+
.find('a').first().append('<span class="qm-ajax-'+ error.type +'"> / AJAX: '+ error.type +'</span>')
|
150 |
+
;
|
151 |
+
}
|
152 |
+
}
|
153 |
+
|
154 |
+
qm.ajax_errors[error.type] = true;
|
155 |
+
|
156 |
+
}
|
157 |
+
|
158 |
+
return event;
|
159 |
+
|
160 |
+
} );
|
161 |
+
|
162 |
+
} );
|
autoloader.php
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
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' );
|
components/admin.php
ADDED
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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_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>';
|
74 |
+
|
75 |
+
echo '<tr>';
|
76 |
+
echo '<td class="qm-ltr">get_current_screen()</td>';
|
77 |
+
echo '<td>';
|
78 |
+
|
79 |
+
if ( is_object( $data['admin'] ) ) {
|
80 |
+
echo '<table class="qm-inner" cellspacing="0">';
|
81 |
+
echo '<tbody>';
|
82 |
+
foreach ( $data['admin'] as $key => $value ) {
|
83 |
+
echo '<tr>';
|
84 |
+
echo "<td class='qm-var'>{$key}:</td>";
|
85 |
+
echo '<td>';
|
86 |
+
echo $value;
|
87 |
+
if ( !empty( $value ) and ( $data['current_screen']->$key != $value ) )
|
88 |
+
echo ' (<a href="http://core.trac.wordpress.org/ticket/14886" class="qm-warn" title="' . esc_attr__( 'This value may not be as expected. Please see WordPress bug #14886.', 'query-monitor' ) . '" target="_blank">!</a>)';
|
89 |
+
echo '</td>';
|
90 |
+
echo '</tr>';
|
91 |
+
}
|
92 |
+
echo '</tbody>';
|
93 |
+
echo '</table>';
|
94 |
+
} else {
|
95 |
+
echo $data['admin'];
|
96 |
+
}
|
97 |
+
|
98 |
+
echo '</td>';
|
99 |
+
echo '</tr>';
|
100 |
+
|
101 |
+
echo '<tr>';
|
102 |
+
echo '<td class="qm-ltr">$pagenow</td>';
|
103 |
+
echo "<td>{$data['pagenow']}</td>";
|
104 |
+
echo '</tr>';
|
105 |
+
|
106 |
+
$screens = array(
|
107 |
+
'edit' => true,
|
108 |
+
'edit-comments' => true,
|
109 |
+
'edit-tags' => true,
|
110 |
+
'link-manager' => true,
|
111 |
+
'plugins' => true,
|
112 |
+
'plugins-network' => true,
|
113 |
+
'sites-network' => true,
|
114 |
+
'themes-network' => true,
|
115 |
+
'upload' => true,
|
116 |
+
'users' => true,
|
117 |
+
'users-network' => true,
|
118 |
+
);
|
119 |
+
|
120 |
+
if ( !empty( $data['current_screen'] ) and isset( $screens[$data['current_screen']->base] ) ) {
|
121 |
+
|
122 |
+
# And now, WordPress' legendary inconsistency comes into play:
|
123 |
+
|
124 |
+
if ( !empty( $data['current_screen']->taxonomy ) )
|
125 |
+
$col = $data['current_screen']->taxonomy;
|
126 |
+
else if ( !empty( $data['current_screen']->post_type ) )
|
127 |
+
$col = $data['current_screen']->post_type . '_posts';
|
128 |
+
else
|
129 |
+
$col = $data['current_screen']->base;
|
130 |
+
|
131 |
+
if ( !empty( $data['current_screen']->post_type ) and empty( $data['current_screen']->taxonomy ) )
|
132 |
+
$cols = $data['current_screen']->post_type . '_posts';
|
133 |
+
else
|
134 |
+
$cols = $data['current_screen']->id;
|
135 |
+
|
136 |
+
if ( 'edit-comments' == $col )
|
137 |
+
$col = 'comments';
|
138 |
+
else if ( 'upload' == $col )
|
139 |
+
$col = 'media';
|
140 |
+
else if ( 'link-manager' == $col )
|
141 |
+
$col = 'link';
|
142 |
+
|
143 |
+
echo '<tr>';
|
144 |
+
echo '<td rowspan="2">' . __( 'Columns', 'query-monitor' ) . '</td>';
|
145 |
+
echo "<td colspan='2'>manage_<span class='qm-current'>{$cols}</span>_columns</td>";
|
146 |
+
echo '</tr>';
|
147 |
+
echo '<tr>';
|
148 |
+
echo "<td colspan='2'>manage_<span class='qm-current'>{$data['current_screen']->id}</span>_sortable_columns</td>";
|
149 |
+
echo '</tr>';
|
150 |
+
|
151 |
+
echo '<tr>';
|
152 |
+
echo '<td rowspan="1">' . __( 'Column', 'query-monitor' ) . '</td>';
|
153 |
+
echo "<td colspan='2'>manage_<span class='qm-current'>{$col}</span>_custom_column</td>";
|
154 |
+
echo '</tr>';
|
155 |
+
|
156 |
+
}
|
157 |
+
|
158 |
+
echo '</tbody>';
|
159 |
+
echo '</table>';
|
160 |
+
echo '</div>';
|
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 );
|
components/authentication.php
ADDED
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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_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>';
|
49 |
+
|
50 |
+
$name = QM_COOKIE;
|
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 |
+
|
60 |
+
echo '<tr>';
|
61 |
+
echo '<td>' . __( 'You can set an authentication cookie which allows you to view Query Monitor output when you’re not logged in.', 'query-monitor' ) . '</td>';
|
62 |
+
echo '</tr>';
|
63 |
+
echo '<tr>';
|
64 |
+
echo '<td><a href="#" onclick="' . $link . '">' . __( 'Set authentication cookie', 'query-monitor' ) . '</a></td>';
|
65 |
+
echo '</tr>';
|
66 |
+
|
67 |
+
} else {
|
68 |
+
|
69 |
+
$text = esc_js( __( 'Authentication cookie cleared.', 'query-monitor' ) );
|
70 |
+
$link = "document.cookie='{$name}=; expires=' + new Date(0).toUTCString() + '; domain={$domain}; path={$path}'; alert('{$text}'); return false;";
|
71 |
+
|
72 |
+
echo '<tr>';
|
73 |
+
echo '<td>' . __( 'You currently have an authentication cookie which allows you to view Query Monitor output.', 'query-monitor' ) . '</td>';
|
74 |
+
echo '</tr>';
|
75 |
+
echo '<tr>';
|
76 |
+
echo '<td><a href="#" onclick="' . $link . '">' . __( 'Clear authentication cookie', 'query-monitor' ) . '</a></td>';
|
77 |
+
echo '</tr>';
|
78 |
+
|
79 |
+
}
|
80 |
+
|
81 |
+
echo '</tbody>';
|
82 |
+
echo '</table>';
|
83 |
+
echo '</div>';
|
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 );
|
components/conditionals.php
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 . '"> </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/db_callers.php
ADDED
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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_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'] ) ) {
|
65 |
+
foreach ( $data['types'] as $type_name => $type_count )
|
66 |
+
echo '<th>' . $type_name . '</th>';
|
67 |
+
}
|
68 |
+
|
69 |
+
echo '<th>' . __( 'Time', 'query-monitor' ) . '</th>';
|
70 |
+
echo '</tr>';
|
71 |
+
echo '</thead>';
|
72 |
+
|
73 |
+
if ( !empty( $data['times'] ) ) {
|
74 |
+
|
75 |
+
echo '<tbody>';
|
76 |
+
|
77 |
+
usort( $data['times'], 'QM_Util::sort' );
|
78 |
+
|
79 |
+
foreach ( $data['times'] as $caller => $row ) {
|
80 |
+
$total_time += $row['ltime'];
|
81 |
+
$total_calls += $row['calls'];
|
82 |
+
$stime = number_format_i18n( $row['ltime'], 4 );
|
83 |
+
$ltime = number_format_i18n( $row['ltime'], 10 );
|
84 |
+
|
85 |
+
echo '<tr>';
|
86 |
+
echo "<td valign='top' class='qm-ltr'>{$row['caller']}</td>";
|
87 |
+
|
88 |
+
foreach ( $data['types'] as $type_name => $type_count ) {
|
89 |
+
if ( isset( $row['types'][$type_name] ) )
|
90 |
+
echo "<td valign='top'>{$row['types'][$type_name]}</td>";
|
91 |
+
else
|
92 |
+
echo "<td valign='top'> </td>";
|
93 |
+
}
|
94 |
+
|
95 |
+
echo "<td valign='top' title='{$ltime}'>{$stime}</td>";
|
96 |
+
echo '</tr>';
|
97 |
+
|
98 |
+
}
|
99 |
+
|
100 |
+
echo '</tbody>';
|
101 |
+
echo '<tfoot>';
|
102 |
+
|
103 |
+
$total_stime = number_format_i18n( $total_time, 4 );
|
104 |
+
$total_ltime = number_format_i18n( $total_time, 10 );
|
105 |
+
|
106 |
+
echo '<tr>';
|
107 |
+
echo '<td> </td>';
|
108 |
+
|
109 |
+
foreach ( $data['types'] as $type_name => $type_count )
|
110 |
+
echo '<td>' . number_format_i18n( $type_count ) . '</td>';
|
111 |
+
|
112 |
+
echo "<td title='{$total_ltime}'>{$total_stime}</td>";
|
113 |
+
echo '</tr>';
|
114 |
+
|
115 |
+
echo '</tfoot>';
|
116 |
+
|
117 |
+
} else {
|
118 |
+
|
119 |
+
echo '<tbody>';
|
120 |
+
echo '<tr>';
|
121 |
+
echo '<td colspan="3" style="text-align:center !important"><em>' . __( 'none', 'query-monitor' ) . '</em></td>';
|
122 |
+
echo '</tr>';
|
123 |
+
echo '</tbody>';
|
124 |
+
|
125 |
+
}
|
126 |
+
|
127 |
+
echo '</table>';
|
128 |
+
echo '</div>';
|
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 );
|
components/db_components.php
ADDED
@@ -0,0 +1,138 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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_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'] ) ) {
|
65 |
+
foreach ( $data['types'] as $type_name => $type_count )
|
66 |
+
echo '<th>' . $type_name . '</th>';
|
67 |
+
}
|
68 |
+
|
69 |
+
echo '<th>' . __( 'Time', 'query-monitor' ) . '</th>';
|
70 |
+
echo '</tr>';
|
71 |
+
echo '</thead>';
|
72 |
+
|
73 |
+
if ( !empty( $data['times'] ) ) {
|
74 |
+
|
75 |
+
echo '<tbody>';
|
76 |
+
|
77 |
+
usort( $data['times'], 'QM_Util::sort' );
|
78 |
+
|
79 |
+
foreach ( $data['times'] as $component => $row ) {
|
80 |
+
$total_time += $row['ltime'];
|
81 |
+
$total_calls += $row['calls'];
|
82 |
+
$stime = number_format_i18n( $row['ltime'], 4 );
|
83 |
+
$ltime = number_format_i18n( $row['ltime'], 10 );
|
84 |
+
|
85 |
+
echo '<tr>';
|
86 |
+
echo "<td valign='top' class='qm-ltr'>{$row['component']}</td>";
|
87 |
+
|
88 |
+
foreach ( $data['types'] as $type_name => $type_count ) {
|
89 |
+
if ( isset( $row['types'][$type_name] ) )
|
90 |
+
echo "<td valign='top'>{$row['types'][$type_name]}</td>";
|
91 |
+
else
|
92 |
+
echo "<td valign='top'> </td>";
|
93 |
+
}
|
94 |
+
|
95 |
+
echo "<td valign='top' title='{$ltime}'>{$stime}</td>";
|
96 |
+
echo '</tr>';
|
97 |
+
|
98 |
+
}
|
99 |
+
|
100 |
+
echo '</tbody>';
|
101 |
+
echo '<tfoot>';
|
102 |
+
|
103 |
+
$total_stime = number_format_i18n( $total_time, 4 );
|
104 |
+
$total_ltime = number_format_i18n( $total_time, 10 );
|
105 |
+
|
106 |
+
echo '<tr>';
|
107 |
+
echo '<td> </td>';
|
108 |
+
|
109 |
+
foreach ( $data['types'] as $type_name => $type_count )
|
110 |
+
echo '<td>' . number_format_i18n( $type_count ) . '</td>';
|
111 |
+
|
112 |
+
echo "<td title='{$total_ltime}'>{$total_stime}</td>";
|
113 |
+
echo '</tr>';
|
114 |
+
echo '</tfoot>';
|
115 |
+
|
116 |
+
} else {
|
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 |
+
|
124 |
+
}
|
125 |
+
|
126 |
+
echo '</table>';
|
127 |
+
echo '</div>';
|
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 );
|
components/db_queries.php
ADDED
@@ -0,0 +1,506 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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_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;
|
140 |
+
|
141 |
+
if ( !empty( $data['errors'] ) ) {
|
142 |
+
|
143 |
+
echo '<div class="qm qm-queries" id="qm-query-errors">';
|
144 |
+
echo '<table cellspacing="0">';
|
145 |
+
echo '<thead>';
|
146 |
+
echo '<tr>';
|
147 |
+
echo '<th colspan="4">' . __( 'Database Errors', 'query-monitor' ) . '</th>';
|
148 |
+
echo '</tr>';
|
149 |
+
echo '<tr>';
|
150 |
+
echo '<th>' . __( 'Query', 'query-monitor' ) . '</th>';
|
151 |
+
echo '<th>' . __( 'Call Stack', 'query-monitor' ) . '</th>';
|
152 |
+
echo '<th>' . __( 'Component', 'query-monitor' ) . '</th>';
|
153 |
+
echo '<th>' . __( 'Error', 'query-monitor' ) . '</th>';
|
154 |
+
echo '</tr>';
|
155 |
+
echo '</thead>';
|
156 |
+
echo '<tbody>';
|
157 |
+
|
158 |
+
foreach ( $data['errors'] as $row )
|
159 |
+
$this->output_query_row( $row, array( 'sql', 'stack', 'component', 'result' ) );
|
160 |
+
|
161 |
+
echo '</tbody>';
|
162 |
+
echo '</table>';
|
163 |
+
echo '</div>';
|
164 |
+
|
165 |
+
}
|
166 |
+
|
167 |
+
if ( !empty( $data['expensive'] ) ) {
|
168 |
+
|
169 |
+
$dp = strlen( substr( strrchr( QM_DB_EXPENSIVE, '.' ), 1 ) );
|
170 |
+
|
171 |
+
echo '<div class="qm qm-queries" id="qm-query-expensive">';
|
172 |
+
echo '<table cellspacing="0">';
|
173 |
+
echo '<thead>';
|
174 |
+
echo '<tr>';
|
175 |
+
echo '<th colspan="5" class="qm-expensive">' . sprintf( __( 'Slow Database Queries (above %ss)', 'query-monitor' ), '<span class="qm-expensive">' . number_format_i18n( QM_DB_EXPENSIVE, $dp ) . '</span>' ) . '</th>';
|
176 |
+
echo '</tr>';
|
177 |
+
echo '<tr>';
|
178 |
+
echo '<th scope="col">' . __( 'Query', 'query-monitor' ) . '</th>';
|
179 |
+
echo '<th scope="col">' . __( 'Caller', 'query-monitor' ) . '</th>';
|
180 |
+
|
181 |
+
if ( isset( $data['expensive'][0]['component'] ) )
|
182 |
+
echo '<th scope="col">' . __( 'Component', 'query-monitor' ) . '</th>';
|
183 |
+
|
184 |
+
if ( isset( $data['expensive'][0]['result'] ) )
|
185 |
+
echo '<th scope="col">' . __( 'Affected Rows', 'query-monitor' ) . '</th>';
|
186 |
+
|
187 |
+
echo '<th>' . __( 'Time', 'query-monitor' ) . '</th>';
|
188 |
+
echo '</tr>';
|
189 |
+
echo '</thead>';
|
190 |
+
echo '<tbody>';
|
191 |
+
|
192 |
+
foreach ( $data['expensive'] as $row )
|
193 |
+
$this->output_query_row( $row, array( 'sql', 'caller', 'component', 'result', 'time' ) );
|
194 |
+
|
195 |
+
echo '</tbody>';
|
196 |
+
echo '</table>';
|
197 |
+
echo '</div>';
|
198 |
+
|
199 |
+
}
|
200 |
+
|
201 |
+
foreach ( $data['dbs'] as $name => $db )
|
202 |
+
$this->output_queries( $name, $db, $data );
|
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 |
+
|
356 |
+
$span = 3;
|
357 |
+
|
358 |
+
if ( $db->has_results )
|
359 |
+
$span++;
|
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' ),
|
373 |
+
number_format_i18n( $db->total_qs ),
|
374 |
+
$name,
|
375 |
+
number_format_i18n( QM_DB_LIMIT )
|
376 |
+
) . '</td>';
|
377 |
+
echo '</tr>';
|
378 |
+
}
|
379 |
+
|
380 |
+
echo '<tr>';
|
381 |
+
echo '<th scope="col">' . __( 'Query', 'query-monitor' ) . $this->build_filter( 'type', array_keys( $db->types ) ) . '</th>';
|
382 |
+
echo '<th scope="col">' . __( 'Caller', 'query-monitor' ) . $this->build_filter( 'caller', array_keys( $data['times'] ) ) . '</th>';
|
383 |
+
|
384 |
+
if ( $db->has_component )
|
385 |
+
echo '<th scope="col">' . __( 'Component', 'query-monitor' ) . $this->build_filter( 'component', array_keys( $data['component_times'] ) ) . '</th>';
|
386 |
+
|
387 |
+
if ( $db->has_results )
|
388 |
+
echo '<th scope="col">' . __( 'Affected Rows', 'query-monitor' ) . '</th>';
|
389 |
+
|
390 |
+
echo '<th scope="col">' . __( 'Time', 'query-monitor' ) . '</th>';
|
391 |
+
echo '</tr>';
|
392 |
+
echo '</thead>';
|
393 |
+
|
394 |
+
if ( !empty( $db->rows ) ) {
|
395 |
+
|
396 |
+
echo '<tbody>';
|
397 |
+
|
398 |
+
foreach ( $db->rows as $i => $row )
|
399 |
+
$this->output_query_row( $row, array( 'sql', 'caller', 'component', 'result', 'time' ) );
|
400 |
+
|
401 |
+
echo '</tbody>';
|
402 |
+
echo '<tfoot>';
|
403 |
+
|
404 |
+
$total_stime = number_format_i18n( $db->total_time, 4 );
|
405 |
+
$total_ltime = number_format_i18n( $db->total_time, 10 );
|
406 |
+
|
407 |
+
echo '<tr>';
|
408 |
+
echo '<td valign="top" colspan="' . ( $span - 1 ) . '">' . sprintf( __( 'Total Queries: %s', 'query-monitor' ), number_format_i18n( $db->total_qs ) ) . '</td>';
|
409 |
+
echo "<td valign='top' title='{$total_ltime}'>{$total_stime}</td>";
|
410 |
+
echo '</tr>';
|
411 |
+
|
412 |
+
echo '<tr class="qm-items-shown qm-hide">';
|
413 |
+
echo '<td valign="top" colspan="' . ( $span - 1 ) . '">' . sprintf( __( 'Queries in filter: %s', 'query-monitor' ), '<span class="qm-items-number">' . number_format_i18n( $db->total_qs ) . '</span>' ) . '</td>';
|
414 |
+
echo "<td valign='top' class='qm-items-time'>{$total_stime}</td>";
|
415 |
+
echo '</tr>';
|
416 |
+
echo '</tfoot>';
|
417 |
+
|
418 |
+
} else {
|
419 |
+
|
420 |
+
echo '<tbody>';
|
421 |
+
echo '<tr>';
|
422 |
+
echo '<td colspan="' . $span . '" style="text-align:center !important"><em>' . __( 'none', 'query-monitor' ) . '</em></td>';
|
423 |
+
echo '</tr>';
|
424 |
+
echo '</tbody>';
|
425 |
+
|
426 |
+
}
|
427 |
+
|
428 |
+
echo '</table>';
|
429 |
+
echo '</div>';
|
430 |
+
|
431 |
+
}
|
432 |
+
|
433 |
+
function output_query_row( array $row, array $cols ) {
|
434 |
+
|
435 |
+
$cols = array_flip( $cols );
|
436 |
+
|
437 |
+
if ( is_null( $row['component'] ) )
|
438 |
+
unset( $cols['component'] );
|
439 |
+
if ( is_null( $row['result'] ) )
|
440 |
+
unset( $cols['result'] );
|
441 |
+
|
442 |
+
$row_attr = array();
|
443 |
+
$stime = number_format_i18n( $row['ltime'], 4 );
|
444 |
+
$ltime = number_format_i18n( $row['ltime'], 10 );
|
445 |
+
$td = self::is_expensive( $row ) ? ' qm-expensive' : '';
|
446 |
+
|
447 |
+
if ( 'SELECT' != $row['type'] )
|
448 |
+
$row['sql'] = "<span class='qm-nonselectsql'>{$row['sql']}</span>";
|
449 |
+
|
450 |
+
if ( is_wp_error( $row['result'] ) ) {
|
451 |
+
$error = $row['result']->get_error_message();
|
452 |
+
$result = "<td valign='top' class='qm-row-result qm-row-error'>{$error}</td>\n";
|
453 |
+
$row_attr['class'] = 'qm-warn';
|
454 |
+
} else {
|
455 |
+
$result = "<td valign='top' class='qm-row-result'>{$row['result']}</td>\n";
|
456 |
+
}
|
457 |
+
|
458 |
+
if ( isset( $cols['sql'] ) )
|
459 |
+
$row_attr['data-qm-db_queries-type'] = $row['type'];
|
460 |
+
if ( isset( $cols['component'] ) )
|
461 |
+
$row_attr['data-qm-db_queries-component'] = $row['component']->name;
|
462 |
+
if ( isset( $cols['caller'] ) )
|
463 |
+
$row_attr['data-qm-db_queries-caller'] = $row['caller_name'];
|
464 |
+
if ( isset( $cols['time'] ) )
|
465 |
+
$row_attr['data-qm-db_queries-time'] = $row['ltime'];
|
466 |
+
|
467 |
+
$stack = esc_attr( $row['stack'] );
|
468 |
+
$attr = '';
|
469 |
+
|
470 |
+
foreach ( $row_attr as $a => $v )
|
471 |
+
$attr .= ' ' . $a . '="' . esc_attr( $v ) . '"';
|
472 |
+
|
473 |
+
echo "<tr{$attr}>";
|
474 |
+
|
475 |
+
if ( isset( $cols['sql'] ) )
|
476 |
+
echo "<td valign='top' class='qm-row-sql qm-ltr qm-sql'>{$row['sql']}</td>";
|
477 |
+
|
478 |
+
if ( isset( $cols['caller'] ) )
|
479 |
+
echo "<td valign='top' class='qm-row-caller qm-ltr' title='{$stack}'>{$row['caller']}</td>";
|
480 |
+
|
481 |
+
if ( isset( $cols['stack'] ) ) {
|
482 |
+
$stack = implode( '<br/>', $row['stack'] );
|
483 |
+
echo "<td valign='top' class='qm-row-caller qm-row-stack qm-ltr'>{$stack}</td>";
|
484 |
+
}
|
485 |
+
|
486 |
+
if ( isset( $cols['component'] ) )
|
487 |
+
echo "<td valign='top' class='qm-row-component'>{$row['component']->name}</td>\n";
|
488 |
+
|
489 |
+
if ( isset( $cols['result'] ) )
|
490 |
+
echo $result;
|
491 |
+
|
492 |
+
if ( isset( $cols['time'] ) )
|
493 |
+
echo "<td valign='top' title='{$ltime}' class='qm-row-time{$td}'>{$stime}</td>\n";
|
494 |
+
|
495 |
+
echo '</tr>';
|
496 |
+
|
497 |
+
}
|
498 |
+
|
499 |
+
}
|
500 |
+
|
501 |
+
function register_qm_db_queries( array $qm ) {
|
502 |
+
$qm['db_queries'] = new QM_Component_DB_Queries;
|
503 |
+
return $qm;
|
504 |
+
}
|
505 |
+
|
506 |
+
add_filter( 'query_monitor_components', 'register_qm_db_queries', 20 );
|
components/environment.php
ADDED
@@ -0,0 +1,354 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
# 'error_log',
|
28 |
+
);
|
29 |
+
|
30 |
+
function __construct() {
|
31 |
+
|
32 |
+
global $wpdb;
|
33 |
+
|
34 |
+
parent::__construct();
|
35 |
+
|
36 |
+
add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 110 );
|
37 |
+
|
38 |
+
# If QueryMonitorDB is in place then we'll use the values which were
|
39 |
+
# caught early before any plugins had a chance to alter them
|
40 |
+
|
41 |
+
foreach ( $this->php_vars as $setting ) {
|
42 |
+
if ( isset( $wpdb->qm_php_vars ) and isset( $wpdb->qm_php_vars[$setting] ) )
|
43 |
+
$val = $wpdb->qm_php_vars[$setting];
|
44 |
+
else
|
45 |
+
$val = ini_get( $setting );
|
46 |
+
$this->data['php']['variables'][$setting]['before'] = $val;
|
47 |
+
}
|
48 |
+
|
49 |
+
if ( isset( $wpdb->qm_php_vars ) and isset( $wpdb->qm_php_vars['error_reporting'] ) )
|
50 |
+
$val = $wpdb->qm_php_vars['error_reporting'];
|
51 |
+
else
|
52 |
+
$val = implode( '<br/>', $this->get_error_reporting() );
|
53 |
+
|
54 |
+
$this->data['php']['variables']['error_reporting']['before'] = $val;
|
55 |
+
|
56 |
+
}
|
57 |
+
|
58 |
+
function get_error_reporting() {
|
59 |
+
|
60 |
+
# @TODO move this into QM_Util and call it in QueryMonitorDB too
|
61 |
+
|
62 |
+
$error_reporting = error_reporting();
|
63 |
+
$levels = array();
|
64 |
+
|
65 |
+
$constants = array(
|
66 |
+
'E_ERROR',
|
67 |
+
'E_WARNING',
|
68 |
+
'E_PARSE',
|
69 |
+
'E_NOTICE',
|
70 |
+
'E_USER_ERROR',
|
71 |
+
'E_USER_WARNING',
|
72 |
+
'E_USER_NOTICE',
|
73 |
+
'E_STRICT',
|
74 |
+
'E_RECOVERABLE_ERROR',
|
75 |
+
'E_DEPRECATED',
|
76 |
+
'E_USER_DEPRECATED',
|
77 |
+
'E_ALL'
|
78 |
+
);
|
79 |
+
|
80 |
+
foreach ( $constants as $level ) {
|
81 |
+
if ( defined( $level ) ) {
|
82 |
+
$c = constant( $level );
|
83 |
+
if ( $error_reporting & $c )
|
84 |
+
$levels[$c] = $level;
|
85 |
+
}
|
86 |
+
}
|
87 |
+
|
88 |
+
return $levels;
|
89 |
+
|
90 |
+
}
|
91 |
+
|
92 |
+
function admin_menu( array $menu ) {
|
93 |
+
|
94 |
+
$menu[] = $this->menu( array(
|
95 |
+
'title' => __( 'Environment', 'query-monitor' )
|
96 |
+
) );
|
97 |
+
return $menu;
|
98 |
+
|
99 |
+
}
|
100 |
+
|
101 |
+
function process() {
|
102 |
+
|
103 |
+
global $wp_version, $blog_id;
|
104 |
+
|
105 |
+
$mysql_vars = array(
|
106 |
+
'key_buffer_size' => true, # Key cache size limit
|
107 |
+
'max_allowed_packet' => false, # Individual query size limit
|
108 |
+
'max_connections' => false, # Max number of client connections
|
109 |
+
'query_cache_limit' => true, # Individual query cache size limit
|
110 |
+
'query_cache_size' => true, # Total cache size limit
|
111 |
+
'query_cache_type' => 'ON' # Query cache on or off
|
112 |
+
);
|
113 |
+
$php_u = '';
|
114 |
+
|
115 |
+
if ( $dbq = $this->get_component( 'db_queries' ) ) {
|
116 |
+
|
117 |
+
foreach ( $dbq->db_objects as $id => $db ) {
|
118 |
+
|
119 |
+
if ( !is_a( $db, 'wpdb' ) )
|
120 |
+
continue;
|
121 |
+
|
122 |
+
$variables = $db->get_results( "
|
123 |
+
SHOW VARIABLES
|
124 |
+
WHERE Variable_name IN ( '" . implode( "', '", array_keys( $mysql_vars ) ) . "' )
|
125 |
+
" );
|
126 |
+
|
127 |
+
$this->data['db'][$id] = array(
|
128 |
+
'version' => mysql_get_server_info( $db->dbh ),
|
129 |
+
'user' => $db->dbuser,
|
130 |
+
'host' => $db->dbhost,
|
131 |
+
'name' => $db->dbname,
|
132 |
+
'vars' => $mysql_vars,
|
133 |
+
'variables' => $variables
|
134 |
+
);
|
135 |
+
|
136 |
+
}
|
137 |
+
|
138 |
+
}
|
139 |
+
|
140 |
+
if ( function_exists( 'posix_getpwuid' ) ) {
|
141 |
+
|
142 |
+
$u = posix_getpwuid( posix_getuid() );
|
143 |
+
$g = posix_getgrgid( $u['gid'] );
|
144 |
+
$php_u = esc_html( $u['name'] . ':' . $g['name'] );
|
145 |
+
|
146 |
+
} else if ( isset( $_SERVER['USER'] ) ) {
|
147 |
+
|
148 |
+
$php_u = esc_html( $_SERVER['USER'] );
|
149 |
+
|
150 |
+
} else if ( function_exists( 'exec' ) ) {
|
151 |
+
|
152 |
+
$php_u = esc_html( exec( 'whoami' ) );
|
153 |
+
|
154 |
+
}
|
155 |
+
|
156 |
+
if ( empty( $php_u ) )
|
157 |
+
$php_u = '<em>' . __( 'Unknown', 'query-monitor' ) . '</em>';
|
158 |
+
|
159 |
+
$this->data['php']['version'] = phpversion();
|
160 |
+
$this->data['php']['user'] = $php_u;
|
161 |
+
|
162 |
+
foreach ( $this->php_vars as $setting )
|
163 |
+
$this->data['php']['variables'][$setting]['after'] = ini_get( $setting );
|
164 |
+
|
165 |
+
$this->data['php']['variables']['error_reporting']['after'] = implode( '<br/>', $this->get_error_reporting() );
|
166 |
+
|
167 |
+
$this->data['wp'] = array(
|
168 |
+
'version' => $wp_version,
|
169 |
+
'WP_DEBUG' => QM_Util::format_bool_constant( 'WP_DEBUG' ),
|
170 |
+
'WP_LOCAL_DEV' => QM_Util::format_bool_constant( 'WP_LOCAL_DEV' ),
|
171 |
+
);
|
172 |
+
|
173 |
+
if ( is_multisite() )
|
174 |
+
$this->data['wp']['blog_id'] = $blog_id;
|
175 |
+
|
176 |
+
$server = explode( ' ', $_SERVER['SERVER_SOFTWARE'] );
|
177 |
+
$server = explode( '/', reset( $server ) );
|
178 |
+
|
179 |
+
if ( isset( $server[1] ) )
|
180 |
+
$server_version = $server[1];
|
181 |
+
else
|
182 |
+
$server_version = '<em>' . __( 'Unknown', 'query-monitor' ) . '</em>';
|
183 |
+
|
184 |
+
$this->data['server'] = array(
|
185 |
+
'name' => $server[0],
|
186 |
+
'version' => $server_version,
|
187 |
+
'address' => $_SERVER['SERVER_ADDR'],
|
188 |
+
'host' => php_uname( 'n' )
|
189 |
+
);
|
190 |
+
|
191 |
+
}
|
192 |
+
|
193 |
+
function output_html( array $args, array $data ) {
|
194 |
+
|
195 |
+
echo '<div class="qm" id="' . $args['id'] . '">';
|
196 |
+
echo '<table cellspacing="0">';
|
197 |
+
echo '<thead>';
|
198 |
+
echo '<tr>';
|
199 |
+
echo '<th colspan="3">' . __( 'Environment', 'query-monitor' ) . '</th>';
|
200 |
+
echo '</tr>';
|
201 |
+
echo '</thead>';
|
202 |
+
echo '<tbody>';
|
203 |
+
|
204 |
+
echo '<tr>';
|
205 |
+
echo '<td rowspan="' . ( 2 + count( $data['php']['variables'] ) ) . '">PHP</td>';
|
206 |
+
echo '<td>version</td>';
|
207 |
+
echo "<td>{$data['php']['version']}</td>";
|
208 |
+
echo '</tr>';
|
209 |
+
echo '<tr>';
|
210 |
+
echo '<td>user</td>';
|
211 |
+
echo "<td>{$data['php']['user']}</td>";
|
212 |
+
echo '</tr>';
|
213 |
+
|
214 |
+
foreach ( $data['php']['variables'] as $key => $val ) {
|
215 |
+
|
216 |
+
$append = '';
|
217 |
+
|
218 |
+
if ( $val['after'] != $val['before'] )
|
219 |
+
$append .= '<br /><span class="qm-info">' . sprintf( __( 'Overridden at runtime from %s', 'query-monitor' ), $val['before'] ) . '</span>';
|
220 |
+
|
221 |
+
echo '<tr>';
|
222 |
+
echo "<td>{$key}</td>";
|
223 |
+
echo "<td>{$val['after']}{$append}</td>";
|
224 |
+
echo '</tr>';
|
225 |
+
}
|
226 |
+
|
227 |
+
if ( isset( $data['db'] ) ) {
|
228 |
+
|
229 |
+
foreach ( $data['db'] as $id => $db ) {
|
230 |
+
|
231 |
+
if ( 1 == count( $data['db'] ) )
|
232 |
+
$name = 'MySQL';
|
233 |
+
else
|
234 |
+
$name = $id . '<br />MySQL';
|
235 |
+
|
236 |
+
echo '<tr>';
|
237 |
+
echo '<td rowspan="' . ( 4 + count( $db['variables'] ) ) . '">' . $name . '</td>';
|
238 |
+
echo '<td>version</td>';
|
239 |
+
echo '<td>' . $db['version'] . '</td>';
|
240 |
+
echo '</tr>';
|
241 |
+
|
242 |
+
echo '<tr>';
|
243 |
+
echo '<td>user</td>';
|
244 |
+
echo '<td>' . $db['user'] . '</td>';
|
245 |
+
echo '</tr>';
|
246 |
+
|
247 |
+
echo '<tr>';
|
248 |
+
echo '<td>host</td>';
|
249 |
+
echo '<td>' . $db['host'] . '</td>';
|
250 |
+
echo '</tr>';
|
251 |
+
|
252 |
+
echo '<tr>';
|
253 |
+
echo '<td>database</td>';
|
254 |
+
echo '<td>' . $db['name'] . '</td>';
|
255 |
+
echo '</tr>';
|
256 |
+
|
257 |
+
echo '<tr>';
|
258 |
+
|
259 |
+
$first = true;
|
260 |
+
$warn = __( "This value may not be optimal. Check the recommended configuration for '%s'.", 'query-monitor' );
|
261 |
+
$search = __( 'https://www.google.com/search?q=mysql+performance+%s', 'query-monitor' );
|
262 |
+
|
263 |
+
foreach ( $db['variables'] as $setting ) {
|
264 |
+
|
265 |
+
$key = $setting->Variable_name;
|
266 |
+
$val = $setting->Value;
|
267 |
+
$prepend = '';
|
268 |
+
$show_warning = false;
|
269 |
+
|
270 |
+
if ( ( true === $db['vars'][$key] ) and empty( $val ) )
|
271 |
+
$show_warning = true;
|
272 |
+
else if ( is_string( $db['vars'][$key] ) and ( $val !== $db['vars'][$key] ) )
|
273 |
+
$show_warning = true;
|
274 |
+
|
275 |
+
if ( $show_warning )
|
276 |
+
$prepend .= ' <span class="qm-info">(<a href="' . esc_url( sprintf( $search, $key ) ) . '" target="_blank" title="' . esc_attr( sprintf( $warn, $key ) ) . '">' . __( 'Help', 'query-monitor' ) . '</a>)</span>';
|
277 |
+
|
278 |
+
if ( is_numeric( $val ) and ( $val >= ( 1024*1024 ) ) )
|
279 |
+
$prepend .= '<br /><span class="qm-info">~' . size_format( $val ) . '</span>';
|
280 |
+
|
281 |
+
$class = ( $show_warning ) ? 'qm-warn' : '';
|
282 |
+
|
283 |
+
if ( !$first )
|
284 |
+
echo "<tr class='{$class}'>";
|
285 |
+
|
286 |
+
$key = esc_html( $key );
|
287 |
+
$val = esc_html( $val );
|
288 |
+
|
289 |
+
echo "<td>{$key}</td>";
|
290 |
+
echo "<td>{$val}{$prepend}</td>";
|
291 |
+
|
292 |
+
echo '</tr>';
|
293 |
+
|
294 |
+
$first = false;
|
295 |
+
|
296 |
+
}
|
297 |
+
|
298 |
+
}
|
299 |
+
|
300 |
+
}
|
301 |
+
|
302 |
+
echo '<tr>';
|
303 |
+
echo '<td rowspan="' . count( $data['wp'] ). '">WordPress</td>';
|
304 |
+
|
305 |
+
$first = true;
|
306 |
+
|
307 |
+
foreach ( $data['wp'] as $key => $val ) {
|
308 |
+
|
309 |
+
if ( !$first )
|
310 |
+
echo "<tr>";
|
311 |
+
|
312 |
+
echo "<td>{$key}</td>";
|
313 |
+
echo "<td>{$val}</td>";
|
314 |
+
echo '</tr>';
|
315 |
+
|
316 |
+
$first = false;
|
317 |
+
|
318 |
+
}
|
319 |
+
|
320 |
+
echo '<tr>';
|
321 |
+
echo '<td rowspan="4">' . __( 'Server', 'query-monitor' ) . '</td>';
|
322 |
+
echo '<td>software</td>';
|
323 |
+
echo "<td>{$data['server']['name']}</td>";
|
324 |
+
echo '</tr>';
|
325 |
+
|
326 |
+
echo '<tr>';
|
327 |
+
echo '<td>version</td>';
|
328 |
+
echo "<td>{$data['server']['version']}</td>";
|
329 |
+
echo '</tr>';
|
330 |
+
|
331 |
+
echo '<tr>';
|
332 |
+
echo '<td>address</td>';
|
333 |
+
echo "<td>{$data['server']['address']}</td>";
|
334 |
+
echo '</tr>';
|
335 |
+
|
336 |
+
echo '<tr>';
|
337 |
+
echo '<td>host</td>';
|
338 |
+
echo "<td>{$data['server']['host']}</td>";
|
339 |
+
echo '</tr>';
|
340 |
+
|
341 |
+
echo '</tbody>';
|
342 |
+
echo '</table>';
|
343 |
+
echo '</div>';
|
344 |
+
|
345 |
+
}
|
346 |
+
|
347 |
+
}
|
348 |
+
|
349 |
+
function register_qm_environment( array $qm ) {
|
350 |
+
$qm['environment'] = new QM_Component_Environment;
|
351 |
+
return $qm;
|
352 |
+
}
|
353 |
+
|
354 |
+
add_filter( 'query_monitor_components', 'register_qm_environment', 90 );
|
components/hooks.php
ADDED
@@ -0,0 +1,185 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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_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>';
|
106 |
+
echo '<th>' . __( 'Hook', 'query-monitor' ) . $this->build_filter( 'name', $data['parts'] ) . '</th>';
|
107 |
+
echo '<th colspan="2">' . __( 'Actions', 'query-monitor' ) . '</th>';
|
108 |
+
echo '<th>' . __( 'Action Component', 'query-monitor' ) . $this->build_filter( 'component', $data['components'] ) . '</th>';
|
109 |
+
echo '</tr>';
|
110 |
+
echo '</thead>';
|
111 |
+
echo '<tbody>';
|
112 |
+
|
113 |
+
foreach ( $data['hooks'] as $hook ) {
|
114 |
+
|
115 |
+
if ( !empty( $data['screen'] ) ) {
|
116 |
+
|
117 |
+
if ( false !== strpos( $hook['name'], $data['screen'] . '.php' ) )
|
118 |
+
$hook['name'] = str_replace( '-' . $data['screen'] . '.php', '-<span class="qm-current">' . $data['screen'] . '.php</span>', $hook['name'] );
|
119 |
+
else
|
120 |
+
$hook['name'] = str_replace( '-' . $data['screen'], '-<span class="qm-current">' . $data['screen'] . '</span>', $hook['name'] );
|
121 |
+
|
122 |
+
}
|
123 |
+
|
124 |
+
$row_attr['data-qm-hooks-name'] = implode( ' ', $hook['parts'] );
|
125 |
+
$row_attr['data-qm-hooks-component'] = implode( ' ', $hook['components'] );
|
126 |
+
|
127 |
+
$attr = '';
|
128 |
+
|
129 |
+
if ( !empty( $hook['actions'] ) )
|
130 |
+
$rowspan = count( $hook['actions'] );
|
131 |
+
else
|
132 |
+
$rowspan = 1;
|
133 |
+
|
134 |
+
foreach ( $row_attr as $a => $v )
|
135 |
+
$attr .= ' ' . $a . '="' . esc_attr( $v ) . '"';
|
136 |
+
|
137 |
+
echo "<tr{$attr}>";
|
138 |
+
|
139 |
+
echo "<td valign='top' rowspan='{$rowspan}'>{$hook['name']}</td>";
|
140 |
+
if ( !empty( $hook['actions'] ) ) {
|
141 |
+
|
142 |
+
$first = true;
|
143 |
+
|
144 |
+
foreach ( $hook['actions'] as $action ) {
|
145 |
+
|
146 |
+
if ( isset( $action['callback']['component'] ) )
|
147 |
+
$component = $action['callback']['component']->name;
|
148 |
+
else
|
149 |
+
$component = '';
|
150 |
+
|
151 |
+
if ( !$first )
|
152 |
+
echo "<tr{$attr}>";
|
153 |
+
|
154 |
+
echo '<td valign="top" class="qm-priority">' . $action['priority'] . '</td>';
|
155 |
+
echo '<td valign="top" class="qm-ltr">';
|
156 |
+
echo esc_html( $action['callback']['name'] );
|
157 |
+
echo '</td>';
|
158 |
+
echo '<td valign="top">';
|
159 |
+
echo esc_html( $component );
|
160 |
+
echo '</td>';
|
161 |
+
echo '</tr>';
|
162 |
+
$first = false;
|
163 |
+
}
|
164 |
+
|
165 |
+
} else {
|
166 |
+
echo '<td colspan="2"> </td>';
|
167 |
+
echo '<td> </td>';
|
168 |
+
}
|
169 |
+
echo '</tr>';
|
170 |
+
}
|
171 |
+
|
172 |
+
echo '</tbody>';
|
173 |
+
echo '</table>';
|
174 |
+
echo '</div>';
|
175 |
+
|
176 |
+
}
|
177 |
+
|
178 |
+
}
|
179 |
+
|
180 |
+
function register_qm_hooks( array $qm ) {
|
181 |
+
$qm['hooks'] = new QM_Component_Hooks;
|
182 |
+
return $qm;
|
183 |
+
}
|
184 |
+
|
185 |
+
add_filter( 'query_monitor_components', 'register_qm_hooks', 80 );
|
components/http.php
ADDED
@@ -0,0 +1,247 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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_HTTP extends QM_Component {
|
18 |
+
|
19 |
+
var $id = 'http';
|
20 |
+
var $http = array();
|
21 |
+
|
22 |
+
function __construct() {
|
23 |
+
|
24 |
+
parent::__construct();
|
25 |
+
|
26 |
+
add_action( 'http_api_debug', array( $this, 'http_debug' ), 99, 5 );
|
27 |
+
add_filter( 'http_request_args', array( $this, 'http_request' ), 99, 2 );
|
28 |
+
add_filter( 'http_response', array( $this, 'http_response' ), 99, 3 );
|
29 |
+
# http://core.trac.wordpress.org/ticket/25747
|
30 |
+
add_filter( 'pre_http_request', array( $this, 'http_response' ), 99, 3 );
|
31 |
+
add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 60 );
|
32 |
+
|
33 |
+
}
|
34 |
+
|
35 |
+
function http_request( array $args, $url ) {
|
36 |
+
$m_start = microtime( true );
|
37 |
+
$key = $m_start . $url;
|
38 |
+
$this->data['http'][$key] = array(
|
39 |
+
'url' => $url,
|
40 |
+
'args' => $args,
|
41 |
+
'start' => $m_start,
|
42 |
+
'trace' => new QM_Backtrace
|
43 |
+
);
|
44 |
+
$args['_qm_key'] = $key;
|
45 |
+
return $args;
|
46 |
+
}
|
47 |
+
|
48 |
+
function http_debug( $param, $action ) {
|
49 |
+
|
50 |
+
switch ( $action ) {
|
51 |
+
|
52 |
+
case 'response':
|
53 |
+
|
54 |
+
$fga = func_get_args();
|
55 |
+
|
56 |
+
list( $response, $action, $class ) = $fga;
|
57 |
+
|
58 |
+
# http://core.trac.wordpress.org/ticket/18732
|
59 |
+
if ( isset( $fga[3] ) )
|
60 |
+
$args = $fga[3];
|
61 |
+
if ( isset( $fga[4] ) )
|
62 |
+
$url = $fga[4];
|
63 |
+
if ( !isset( $args['_qm_key'] ) )
|
64 |
+
return;
|
65 |
+
|
66 |
+
if ( !empty( $class ) )
|
67 |
+
$this->data['http'][$args['_qm_key']]['transport'] = str_replace( 'wp_http_', '', strtolower( $class ) );
|
68 |
+
else
|
69 |
+
$this->data['http'][$args['_qm_key']]['transport'] = false;
|
70 |
+
|
71 |
+
if ( is_wp_error( $response ) )
|
72 |
+
$this->http_response( $response, $args, $url );
|
73 |
+
|
74 |
+
break;
|
75 |
+
|
76 |
+
case 'transports_list':
|
77 |
+
# Nothing
|
78 |
+
break;
|
79 |
+
|
80 |
+
}
|
81 |
+
|
82 |
+
}
|
83 |
+
|
84 |
+
function http_response( $response, array $args, $url ) {
|
85 |
+
$this->data['http'][$args['_qm_key']]['end'] = microtime( true );
|
86 |
+
$this->data['http'][$args['_qm_key']]['response'] = $response;
|
87 |
+
return $response;
|
88 |
+
}
|
89 |
+
|
90 |
+
function admin_menu( array $menu ) {
|
91 |
+
|
92 |
+
$count = isset( $this->data['http'] ) ? count( $this->data['http'] ) : 0;
|
93 |
+
|
94 |
+
$title = ( empty( $count ) )
|
95 |
+
? __( 'HTTP Requests', 'query-monitor' )
|
96 |
+
: __( 'HTTP Requests (%s)', 'query-monitor' );
|
97 |
+
|
98 |
+
$menu[] = $this->menu( array(
|
99 |
+
'title' => sprintf( $title, number_format_i18n( $count ) )
|
100 |
+
) );
|
101 |
+
return $menu;
|
102 |
+
|
103 |
+
}
|
104 |
+
|
105 |
+
function output_html( array $args, array $data ) {
|
106 |
+
|
107 |
+
$total_time = 0;
|
108 |
+
|
109 |
+
echo '<div class="qm" id="' . $args['id'] . '">';
|
110 |
+
echo '<table cellspacing="0">';
|
111 |
+
echo '<thead>';
|
112 |
+
echo '<tr>';
|
113 |
+
echo '<th>' . __( 'HTTP Request', 'query-monitor' ) . '</th>';
|
114 |
+
echo '<th>' . __( 'Response', 'query-monitor' ) . '</th>';
|
115 |
+
echo '<th>' . __( 'Transport', 'query-monitor' ) . '</th>';
|
116 |
+
echo '<th>' . __( 'Call Stack', 'query-monitor' ) . '</th>';
|
117 |
+
echo '<th>' . __( 'Component', 'query-monitor' ) . '</th>';
|
118 |
+
echo '<th>' . __( 'Timeout', 'query-monitor' ) . '</th>';
|
119 |
+
echo '<th>' . __( 'Time', 'query-monitor' ) . '</th>';
|
120 |
+
echo '</tr>';
|
121 |
+
echo '</thead>';
|
122 |
+
|
123 |
+
if ( !empty( $data['http'] ) ) {
|
124 |
+
|
125 |
+
echo '<tbody>';
|
126 |
+
|
127 |
+
foreach ( $data['http'] as $row ) {
|
128 |
+
$funcs = array();
|
129 |
+
|
130 |
+
if ( isset( $row['response'] ) ) {
|
131 |
+
|
132 |
+
$ltime = ( $row['end'] - $row['start'] );
|
133 |
+
$total_time += $ltime;
|
134 |
+
$stime = number_format_i18n( $ltime, 4 );
|
135 |
+
$ltime = number_format_i18n( $ltime, 10 );
|
136 |
+
|
137 |
+
if ( is_wp_error( $row['response'] ) ) {
|
138 |
+
$response = $row['response']->get_error_message();
|
139 |
+
$css = 'qm-warn';
|
140 |
+
} else {
|
141 |
+
$response = wp_remote_retrieve_response_code( $row['response'] );
|
142 |
+
$msg = wp_remote_retrieve_response_message( $row['response'] );
|
143 |
+
$css = '';
|
144 |
+
|
145 |
+
if ( empty( $response ) )
|
146 |
+
$response = __( 'n/a', 'query-monitor' );
|
147 |
+
else
|
148 |
+
$response = esc_html( $response . ' ' . $msg );
|
149 |
+
|
150 |
+
if ( intval( $response ) >= 400 )
|
151 |
+
$css = 'qm-warn';
|
152 |
+
|
153 |
+
}
|
154 |
+
|
155 |
+
} else {
|
156 |
+
|
157 |
+
# @TODO test if the timeout has actually passed. if not, the request was erroneous rather than timed out
|
158 |
+
|
159 |
+
$total_time += $row['args']['timeout'];
|
160 |
+
|
161 |
+
$ltime = '';
|
162 |
+
$stime = number_format_i18n( $row['args']['timeout'], 4 );
|
163 |
+
$response = __( 'Request timed out', 'query-monitor' );
|
164 |
+
$css = 'qm-warn';
|
165 |
+
|
166 |
+
}
|
167 |
+
|
168 |
+
$method = $row['args']['method'];
|
169 |
+
if ( !$row['args']['blocking'] )
|
170 |
+
$method .= ' ' . _x( '(non-blocking)', 'non-blocking HTTP transport', 'query-monitor' );
|
171 |
+
$url = str_replace( array(
|
172 |
+
'=',
|
173 |
+
'&',
|
174 |
+
'?',
|
175 |
+
), array(
|
176 |
+
'<span class="qm-param">=</span>',
|
177 |
+
'<br /><span class="qm-param">&</span>',
|
178 |
+
'<br /><span class="qm-param">?</span>',
|
179 |
+
), $row['url'] );
|
180 |
+
|
181 |
+
if ( isset( $row['transport'] ) )
|
182 |
+
$transport = $row['transport'];
|
183 |
+
else
|
184 |
+
$transport = '';
|
185 |
+
|
186 |
+
$stack = $row['trace']->get_stack();
|
187 |
+
|
188 |
+
foreach ( $stack as & $trace ) {
|
189 |
+
foreach ( array( 'WP_Http', 'wp_remote_', 'fetch_rss', 'fetch_feed', 'SimplePie', 'download_url' ) as $skip ) {
|
190 |
+
if ( 0 === strpos( $trace, $skip ) ) {
|
191 |
+
$trace = sprintf( '<span class="qm-na">%s</span>', $trace );
|
192 |
+
break;
|
193 |
+
}
|
194 |
+
}
|
195 |
+
}
|
196 |
+
|
197 |
+
$component = QM_Util::get_backtrace_component( $row['trace'] );
|
198 |
+
|
199 |
+
$stack = implode( '<br />', $stack );
|
200 |
+
echo "
|
201 |
+
<tr class='{$css}'>\n
|
202 |
+
<td valign='top' class='qm-url qm-ltr'>{$method}<br/>{$url}</td>\n
|
203 |
+
<td valign='top'>{$response}</td>\n
|
204 |
+
<td valign='top'>{$transport}</td>\n
|
205 |
+
<td valign='top' class='qm-ltr'>{$stack}</td>\n
|
206 |
+
<td valign='top'>{$component->name}</td>\n
|
207 |
+
<td valign='top'>{$row['args']['timeout']}</td>\n
|
208 |
+
<td valign='top' title='{$ltime}'>{$stime}</td>\n
|
209 |
+
</tr>\n
|
210 |
+
";
|
211 |
+
}
|
212 |
+
|
213 |
+
echo '</tbody>';
|
214 |
+
echo '<tfoot>';
|
215 |
+
|
216 |
+
$total_stime = number_format_i18n( $total_time, 4 );
|
217 |
+
$total_ltime = number_format_i18n( $total_time, 10 );
|
218 |
+
|
219 |
+
echo '<tr>';
|
220 |
+
echo '<td colspan="6"> </td>';
|
221 |
+
echo "<td title='{$total_ltime}'>{$total_stime}</td>";
|
222 |
+
echo '</tr>';
|
223 |
+
echo '</tfoot>';
|
224 |
+
|
225 |
+
} else {
|
226 |
+
|
227 |
+
echo '<tbody>';
|
228 |
+
echo '<tr>';
|
229 |
+
echo '<td colspan="7" style="text-align:center !important"><em>' . __( 'none', 'query-monitor' ) . '</em></td>';
|
230 |
+
echo '</tr>';
|
231 |
+
echo '</tbody>';
|
232 |
+
|
233 |
+
}
|
234 |
+
|
235 |
+
echo '</table>';
|
236 |
+
echo '</div>';
|
237 |
+
|
238 |
+
}
|
239 |
+
|
240 |
+
}
|
241 |
+
|
242 |
+
function register_qm_http( array $qm ) {
|
243 |
+
$qm['http'] = new QM_Component_HTTP;
|
244 |
+
return $qm;
|
245 |
+
}
|
246 |
+
|
247 |
+
add_filter( 'query_monitor_components', 'register_qm_http', 110 );
|
components/overview.php
ADDED
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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_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>';
|
70 |
+
|
71 |
+
$time_usage .= '<br /><span class="qm-info">' . sprintf( __( '%1$s%% of %2$ss limit', 'query-monitor' ), number_format_i18n( $data['time_usage'], 1 ), number_format_i18n( $data['time_limit'] ) ) . '</span>';
|
72 |
+
|
73 |
+
echo '<thead>';
|
74 |
+
echo '<tr>';
|
75 |
+
echo '<th scope="col">' . __( 'Page generation time', 'query-monitor' ) . '</th>';
|
76 |
+
echo '<th scope="col">' . __( 'Peak memory usage', 'query-monitor' ) . '</th>';
|
77 |
+
if ( isset( $db_query_num ) ) {
|
78 |
+
echo '<th scope="col">' . __( 'Database query time', 'query-monitor' ) . '</th>';
|
79 |
+
echo '<th scope="col">' . __( 'Database queries', 'query-monitor' ) . '</th>';
|
80 |
+
}
|
81 |
+
echo '</tr>';
|
82 |
+
echo '</thead>';
|
83 |
+
|
84 |
+
echo '<tbody>';
|
85 |
+
echo '<tr>';
|
86 |
+
echo "<td><span title='{$total_ltime}'>{$total_stime}</span>{$time_usage}</td>";
|
87 |
+
echo '<td><span title="' . esc_attr( sprintf( __( '%s bytes', 'query-monitor' ), number_format_i18n( $data['memory'] ) ) ) . '">' . sprintf( __( '%s kB', 'query-monitor' ), number_format_i18n( $data['memory'] / 1024 ) ) . '</span>' . $memory_usage . '</td>';
|
88 |
+
if ( isset( $db_query_num ) ) {
|
89 |
+
echo "<td title='{$db_ltime}'>{$db_stime}</td>";
|
90 |
+
echo '<td>';
|
91 |
+
|
92 |
+
foreach ( $db_query_num as $type_name => $type_count )
|
93 |
+
$db_query_types[] = sprintf( '%1$s: %2$s', $type_name, number_format_i18n( $type_count ) );
|
94 |
+
|
95 |
+
echo implode( '<br />', $db_query_types );
|
96 |
+
|
97 |
+
echo '</td>';
|
98 |
+
}
|
99 |
+
echo '</tr>';
|
100 |
+
echo '</tbody>';
|
101 |
+
|
102 |
+
echo '</table>';
|
103 |
+
echo '</div>';
|
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 );
|
components/php_errors.php
ADDED
@@ -0,0 +1,238 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
$all_errors = array();
|
73 |
+
|
74 |
+
foreach ( $data['errors'] as $type => $errors ) {
|
75 |
+
|
76 |
+
foreach ( $errors as $key => $error ) {
|
77 |
+
|
78 |
+
$all_errors[$key] = $key;
|
79 |
+
|
80 |
+
header( sprintf( 'X-QM-Error-%s: %s',
|
81 |
+
$key,
|
82 |
+
json_encode( $error )
|
83 |
+
) );
|
84 |
+
|
85 |
+
}
|
86 |
+
|
87 |
+
}
|
88 |
+
|
89 |
+
header( sprintf( 'X-QM-Errors: %s',
|
90 |
+
json_encode( $all_errors )
|
91 |
+
) );
|
92 |
+
|
93 |
+
}
|
94 |
+
|
95 |
+
function output_html( array $args, array $data ) {
|
96 |
+
|
97 |
+
if ( empty( $data['errors'] ) )
|
98 |
+
return;
|
99 |
+
|
100 |
+
echo '<div class="qm" id="' . $args['id'] . '">';
|
101 |
+
echo '<table cellspacing="0">';
|
102 |
+
echo '<thead>';
|
103 |
+
echo '<tr>';
|
104 |
+
echo '<th colspan="2">' . __( 'PHP Error', 'query-monitor' ) . '</th>';
|
105 |
+
echo '<th>' . __( 'File', 'query-monitor' ) . '</th>';
|
106 |
+
echo '<th>' . __( 'Line', 'query-monitor' ) . '</th>';
|
107 |
+
echo '<th>' . __( 'Call Stack', 'query-monitor' ) . '</th>';
|
108 |
+
echo '<th>' . __( 'Component', 'query-monitor' ) . '</th>';
|
109 |
+
echo '</tr>';
|
110 |
+
echo '</thead>';
|
111 |
+
echo '<tbody>';
|
112 |
+
|
113 |
+
$types = array(
|
114 |
+
'warning' => __( 'Warning', 'query-monitor' ),
|
115 |
+
'notice' => __( 'Notice', 'query-monitor' ),
|
116 |
+
'strict' => __( 'Strict', 'query-monitor' ),
|
117 |
+
);
|
118 |
+
|
119 |
+
foreach ( $types as $type => $title ) {
|
120 |
+
|
121 |
+
if ( isset( $data['errors'][$type] ) ) {
|
122 |
+
|
123 |
+
echo '<tr>';
|
124 |
+
if ( count( $data['errors'][$type] ) > 1 )
|
125 |
+
echo '<td rowspan="' . count( $data['errors'][$type] ) . '">' . $title . '</td>';
|
126 |
+
else
|
127 |
+
echo '<td>' . $title . '</td>';
|
128 |
+
$first = true;
|
129 |
+
|
130 |
+
foreach ( $data['errors'][$type] as $error ) {
|
131 |
+
|
132 |
+
if ( !$first )
|
133 |
+
echo '<tr>';
|
134 |
+
|
135 |
+
$stack = $error->trace->get_stack();
|
136 |
+
$component = QM_Util::get_backtrace_component( $error->trace );
|
137 |
+
|
138 |
+
if ( empty( $stack ) )
|
139 |
+
$stack = '<em>' . __( 'none', 'query-monitor' ) . '</em>';
|
140 |
+
else
|
141 |
+
$stack = implode( '<br />', $stack );
|
142 |
+
|
143 |
+
$message = str_replace( "href='function.", "target='_blank' href='http://php.net/function.", $error->message );
|
144 |
+
|
145 |
+
echo '<td>' . $message . '</td>';
|
146 |
+
echo '<td title="' . esc_attr( $error->file ) . '">' . esc_html( $error->filename ) . '</td>';
|
147 |
+
echo '<td>' . esc_html( $error->line ) . '</td>';
|
148 |
+
echo '<td class="qm-ltr">' . $stack . '</td>';
|
149 |
+
echo '<td>' . $component->name . '</td>';
|
150 |
+
echo '</tr>';
|
151 |
+
|
152 |
+
$first = false;
|
153 |
+
|
154 |
+
}
|
155 |
+
|
156 |
+
}
|
157 |
+
|
158 |
+
}
|
159 |
+
|
160 |
+
echo '</tbody>';
|
161 |
+
echo '</table>';
|
162 |
+
echo '</div>';
|
163 |
+
|
164 |
+
}
|
165 |
+
|
166 |
+
function error_handler( $errno, $message, $file = null, $line = null ) {
|
167 |
+
|
168 |
+
#if ( !( error_reporting() & $errno ) )
|
169 |
+
# return false;
|
170 |
+
|
171 |
+
switch ( $errno ) {
|
172 |
+
|
173 |
+
case E_WARNING:
|
174 |
+
case E_USER_WARNING:
|
175 |
+
$type = 'warning';
|
176 |
+
break;
|
177 |
+
|
178 |
+
case E_NOTICE:
|
179 |
+
case E_USER_NOTICE:
|
180 |
+
$type = 'notice';
|
181 |
+
break;
|
182 |
+
|
183 |
+
case E_STRICT:
|
184 |
+
$type = 'strict';
|
185 |
+
break;
|
186 |
+
|
187 |
+
default:
|
188 |
+
return false;
|
189 |
+
break;
|
190 |
+
|
191 |
+
}
|
192 |
+
|
193 |
+
if ( error_reporting() > 0 ) {
|
194 |
+
|
195 |
+
$trace = new QM_Backtrace;
|
196 |
+
$func = reset( $trace->get_stack() );
|
197 |
+
$key = md5( $message . $file . $line . $func );
|
198 |
+
|
199 |
+
$filename = QM_Util::standard_dir( $file, '' );
|
200 |
+
|
201 |
+
if ( isset( $this->data['errors'][$type][$key] ) ) {
|
202 |
+
$this->data['errors'][$type][$key]->calls++;
|
203 |
+
} else {
|
204 |
+
$this->data['errors'][$type][$key] = (object) array(
|
205 |
+
'errno' => $errno,
|
206 |
+
'type' => $type,
|
207 |
+
'message' => $message,
|
208 |
+
'file' => $file,
|
209 |
+
'filename' => $filename,
|
210 |
+
'line' => $line,
|
211 |
+
'trace' => $trace,
|
212 |
+
'calls' => 1
|
213 |
+
);
|
214 |
+
}
|
215 |
+
|
216 |
+
}
|
217 |
+
|
218 |
+
return apply_filters( 'query_monitor_php_errors_return_value', true );
|
219 |
+
|
220 |
+
}
|
221 |
+
|
222 |
+
}
|
223 |
+
|
224 |
+
function register_qm_php_errors( array $qm ) {
|
225 |
+
$qm['php_errors'] = new QM_Component_PHP_Errors;
|
226 |
+
return $qm;
|
227 |
+
}
|
228 |
+
|
229 |
+
function qm_php_errors_return_value( $return ) {
|
230 |
+
# If Xdebug is enabled we'll return false so Xdebug's error handler can do its thing.
|
231 |
+
if ( function_exists( 'xdebug_is_enabled' ) and xdebug_is_enabled() )
|
232 |
+
return false;
|
233 |
+
else
|
234 |
+
return $return;
|
235 |
+
}
|
236 |
+
|
237 |
+
add_filter( 'query_monitor_components', 'register_qm_php_errors', 120 );
|
238 |
+
add_filter( 'query_monitor_php_errors_return_value', 'qm_php_errors_return_value' );
|
components/query_vars.php
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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/redirects.php
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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_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;
|
36 |
+
|
37 |
+
$trace = new QM_Backtrace;
|
38 |
+
|
39 |
+
header( sprintf( 'X-QM-Redirect-Trace: %s',
|
40 |
+
implode( ', ', $trace->get_stack() )
|
41 |
+
) );
|
42 |
+
|
43 |
+
return $location;
|
44 |
+
|
45 |
+
}
|
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 );
|
components/theme.php
ADDED
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 );
|
components/transients.php
ADDED
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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_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>';
|
56 |
+
echo '<th>' . __( 'Transient Set', 'query-monitor' ) . '</th>';
|
57 |
+
if ( is_multisite() )
|
58 |
+
echo '<th>' . __( 'Type', 'query-monitor' ) . '</th>';
|
59 |
+
if ( !empty( $data['trans'] ) and !is_null( $data['trans'][0]['expiration'] ) )
|
60 |
+
echo '<th>' . __( 'Expiration', 'query-monitor' ) . '</th>';
|
61 |
+
echo '<th>' . __( 'Call Stack', 'query-monitor' ) . '</th>';
|
62 |
+
echo '<th>' . __( 'Component', 'query-monitor' ) . '</th>';
|
63 |
+
echo '</tr>';
|
64 |
+
echo '</thead>';
|
65 |
+
|
66 |
+
if ( !empty( $data['trans'] ) ) {
|
67 |
+
|
68 |
+
echo '<tbody>';
|
69 |
+
|
70 |
+
foreach ( $data['trans'] as $row ) {
|
71 |
+
$stack = $row['trace']->get_stack();
|
72 |
+
$transient = str_replace( array(
|
73 |
+
'_site_transient_',
|
74 |
+
'_transient_'
|
75 |
+
), '', $row['transient'] );
|
76 |
+
$type = ( is_multisite() ) ? "<td valign='top'>{$row['type']}</td>\n" : '';
|
77 |
+
if ( 0 === $row['expiration'] )
|
78 |
+
$row['expiration'] = '<em>' . __( 'none', 'query-monitor' ) . '</em>';
|
79 |
+
$expiration = ( !is_null( $row['expiration'] ) ) ? "<td valign='top'>{$row['expiration']}</td>\n" : '';
|
80 |
+
|
81 |
+
foreach ( $stack as & $trace ) {
|
82 |
+
foreach ( array( 'set_transient', 'set_site_transient' ) as $skip ) {
|
83 |
+
if ( 0 === strpos( $trace, $skip ) ) {
|
84 |
+
$trace = sprintf( '<span class="qm-na">%s</span>', $trace );
|
85 |
+
break;
|
86 |
+
}
|
87 |
+
}
|
88 |
+
}
|
89 |
+
|
90 |
+
$component = QM_Util::get_backtrace_component( $row['trace'] );
|
91 |
+
|
92 |
+
$stack = implode( '<br />', $stack );
|
93 |
+
echo "
|
94 |
+
<tr>\n
|
95 |
+
<td valign='top'>{$transient}</td>\n
|
96 |
+
{$type}
|
97 |
+
{$expiration}
|
98 |
+
<td valign='top' class='qm-ltr'>{$stack}</td>\n
|
99 |
+
<td valign='top'>{$component->name}</td>\n
|
100 |
+
</tr>\n
|
101 |
+
";
|
102 |
+
}
|
103 |
+
|
104 |
+
echo '</tbody>';
|
105 |
+
|
106 |
+
} else {
|
107 |
+
|
108 |
+
echo '<tbody>';
|
109 |
+
echo '<tr>';
|
110 |
+
echo '<td colspan="4" style="text-align:center !important"><em>' . __( 'none', 'query-monitor' ) . '</em></td>';
|
111 |
+
echo '</tr>';
|
112 |
+
echo '</tbody>';
|
113 |
+
|
114 |
+
}
|
115 |
+
|
116 |
+
echo '</table>';
|
117 |
+
echo '</div>';
|
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' )
|
127 |
+
: __( 'Transients Set (%s)', 'query-monitor' );
|
128 |
+
|
129 |
+
$menu[] = $this->menu( array(
|
130 |
+
'title' => sprintf( $title, number_format_i18n( $count ) )
|
131 |
+
) );
|
132 |
+
return $menu;
|
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 );
|
composer.json
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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" : [
|
8 |
+
{
|
9 |
+
"name" : "John Blackbourn",
|
10 |
+
"homepage": "https://johnblackbourn.com/"
|
11 |
+
}
|
12 |
+
],
|
13 |
+
"require": {
|
14 |
+
"composer/installers": "~1.0"
|
15 |
+
}
|
16 |
+
}
|
query-monitor.php
ADDED
@@ -0,0 +1,328 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Plugin Name: Query Monitor
|
4 |
+
Description: Monitoring of database queries, hooks, conditionals and more.
|
5 |
+
Version: 2.5.2
|
6 |
+
Plugin URI: https://github.com/johnbillion/QueryMonitor
|
7 |
+
Author: John Blackbourn
|
8 |
+
Author URI: https://johnblackbourn.com/
|
9 |
+
Text Domain: query-monitor
|
10 |
+
Domain Path: /languages/
|
11 |
+
License: GPL v2 or later
|
12 |
+
|
13 |
+
Copyright 2013 John Blackbourn
|
14 |
+
|
15 |
+
This program is free software; you can redistribute it and/or modify
|
16 |
+
it under the terms of the GNU General Public License as published by
|
17 |
+
the Free Software Foundation; either version 2 of the License, or
|
18 |
+
(at your option) any later version.
|
19 |
+
|
20 |
+
This program is distributed in the hope that it will be useful,
|
21 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
22 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
23 |
+
GNU General Public License for more details.
|
24 |
+
|
25 |
+
*/
|
26 |
+
|
27 |
+
defined( 'ABSPATH' ) or die();
|
28 |
+
|
29 |
+
require_once dirname( __FILE__ ) . '/autoloader.php';
|
30 |
+
|
31 |
+
class QueryMonitor extends QM_Plugin {
|
32 |
+
|
33 |
+
protected $components = array();
|
34 |
+
protected $did_footer = false;
|
35 |
+
|
36 |
+
public function __construct( $file ) {
|
37 |
+
|
38 |
+
# Actions
|
39 |
+
add_action( 'init', array( $this, 'action_init' ) );
|
40 |
+
add_action( 'admin_footer', array( $this, 'action_footer' ), 999 );
|
41 |
+
add_action( 'wp_footer', array( $this, 'action_footer' ), 999 );
|
42 |
+
add_action( 'login_footer', array( $this, 'action_footer' ), 999 );
|
43 |
+
add_action( 'admin_bar_menu', array( $this, 'action_admin_bar_menu' ), 999 );
|
44 |
+
add_action( 'shutdown', array( $this, 'action_shutdown' ), 0 );
|
45 |
+
|
46 |
+
# Filters
|
47 |
+
add_filter( 'pre_update_option_active_plugins', array( $this, 'filter_active_plugins' ) );
|
48 |
+
add_filter( 'pre_update_site_option_active_sitewide_plugins', array( $this, 'filter_active_sitewide_plugins' ) );
|
49 |
+
|
50 |
+
# [Dea|A]ctivation
|
51 |
+
register_activation_hook( __FILE__, array( $this, 'activate' ) );
|
52 |
+
register_deactivation_hook( __FILE__, array( $this, 'deactivate' ) );
|
53 |
+
|
54 |
+
# Parent setup:
|
55 |
+
parent::__construct( $file );
|
56 |
+
|
57 |
+
foreach ( glob( $this->plugin_path( 'components/*.php' ) ) as $component )
|
58 |
+
include $component;
|
59 |
+
|
60 |
+
foreach ( apply_filters( 'query_monitor_components', array() ) as $component )
|
61 |
+
$this->add_component( $component );
|
62 |
+
|
63 |
+
}
|
64 |
+
|
65 |
+
public function add_component( QM_Component $component ) {
|
66 |
+
$this->components[$component->id] = $component;
|
67 |
+
}
|
68 |
+
|
69 |
+
public function get_component( $id ) {
|
70 |
+
if ( isset( $this->components[$id] ) )
|
71 |
+
return $this->components[$id];
|
72 |
+
return false;
|
73 |
+
}
|
74 |
+
|
75 |
+
public function get_components() {
|
76 |
+
return $this->components;
|
77 |
+
}
|
78 |
+
|
79 |
+
public function activate( $sitewide = false ) {
|
80 |
+
|
81 |
+
if ( $admins = QM_Util::get_admins() )
|
82 |
+
$admins->add_cap( 'view_query_monitor' );
|
83 |
+
|
84 |
+
if ( !file_exists( $db = WP_CONTENT_DIR . '/db.php' ) and function_exists( 'symlink' ) )
|
85 |
+
@symlink( $this->plugin_path( 'wp-content/db.php' ), $db );
|
86 |
+
|
87 |
+
if ( $sitewide )
|
88 |
+
update_site_option( 'active_sitewide_plugins', $this->filter_active_sitewide_plugins( get_site_option( 'active_sitewide_plugins' ) ) );
|
89 |
+
else
|
90 |
+
update_option( 'active_plugins', $this->filter_active_plugins( get_option( 'active_plugins' ) ) );
|
91 |
+
|
92 |
+
}
|
93 |
+
|
94 |
+
public function deactivate() {
|
95 |
+
|
96 |
+
if ( $admins = QM_Util::get_admins() )
|
97 |
+
$admins->remove_cap( 'view_query_monitor' );
|
98 |
+
|
99 |
+
# Only delete db.php if it belongs to Query Monitor
|
100 |
+
if ( class_exists( 'QueryMonitorDB' ) )
|
101 |
+
unlink( WP_CONTENT_DIR . '/db.php' );
|
102 |
+
|
103 |
+
}
|
104 |
+
|
105 |
+
public function action_admin_bar_menu( WP_Admin_Bar $wp_admin_bar ) {
|
106 |
+
|
107 |
+
if ( !$this->show_query_monitor() )
|
108 |
+
return;
|
109 |
+
|
110 |
+
$class = implode( ' ', array( 'hide-if-js', QM_Util::wpv() ) );
|
111 |
+
$title = __( 'Query Monitor', 'query-monitor' );
|
112 |
+
|
113 |
+
$wp_admin_bar->add_menu( array(
|
114 |
+
'id' => 'query-monitor',
|
115 |
+
'title' => $title,
|
116 |
+
'href' => '#qm-overview',
|
117 |
+
'meta' => array(
|
118 |
+
'classname' => $class
|
119 |
+
)
|
120 |
+
) );
|
121 |
+
|
122 |
+
$wp_admin_bar->add_menu( array(
|
123 |
+
'parent' => 'query-monitor',
|
124 |
+
'id' => 'query-monitor-placeholder',
|
125 |
+
'title' => $title,
|
126 |
+
'href' => '#qm-overview'
|
127 |
+
) );
|
128 |
+
|
129 |
+
}
|
130 |
+
|
131 |
+
public function js_admin_bar_menu() {
|
132 |
+
|
133 |
+
$class = implode( ' ', apply_filters( 'query_monitor_class', array( QM_Util::wpv() ) ) );
|
134 |
+
$title = implode( ' / ', apply_filters( 'query_monitor_title', array() ) );
|
135 |
+
|
136 |
+
if ( empty( $title ) )
|
137 |
+
$title = __( 'Query Monitor', 'query-monitor' );
|
138 |
+
|
139 |
+
$admin_bar_menu = array(
|
140 |
+
'top' => array(
|
141 |
+
'title' => sprintf( '<span class="ab-icon">QM</span><span class="ab-label">%s</span>', $title ),
|
142 |
+
'classname' => $class
|
143 |
+
),
|
144 |
+
'sub' => array()
|
145 |
+
);
|
146 |
+
|
147 |
+
foreach ( apply_filters( 'query_monitor_menus', array() ) as $menu )
|
148 |
+
$admin_bar_menu['sub'][] = $menu;
|
149 |
+
|
150 |
+
return $admin_bar_menu;
|
151 |
+
|
152 |
+
}
|
153 |
+
|
154 |
+
public function show_query_monitor() {
|
155 |
+
|
156 |
+
if ( !did_action( 'plugins_loaded' ) )
|
157 |
+
return false;
|
158 |
+
|
159 |
+
if ( isset( $this->show_query_monitor ) )
|
160 |
+
return $this->show_query_monitor;
|
161 |
+
|
162 |
+
if ( isset( $_REQUEST['wp_customize'] ) and 'on' == $_REQUEST['wp_customize'] )
|
163 |
+
return $this->show_query_monitor = false;
|
164 |
+
|
165 |
+
if ( is_multisite() ) {
|
166 |
+
if ( current_user_can( 'manage_network_options' ) )
|
167 |
+
return $this->show_query_monitor = true;
|
168 |
+
} else if ( current_user_can( 'view_query_monitor' ) ) {
|
169 |
+
return $this->show_query_monitor = true;
|
170 |
+
}
|
171 |
+
|
172 |
+
if ( $auth = $this->get_component( 'authentication' ) )
|
173 |
+
return $this->show_query_monitor = $auth->show_query_monitor();
|
174 |
+
|
175 |
+
return $this->show_query_monitor = false;
|
176 |
+
|
177 |
+
}
|
178 |
+
|
179 |
+
public function action_footer() {
|
180 |
+
|
181 |
+
$this->did_footer = true;
|
182 |
+
|
183 |
+
}
|
184 |
+
|
185 |
+
public function action_shutdown() {
|
186 |
+
|
187 |
+
if ( QM_Util::is_ajax() )
|
188 |
+
$this->output_ajax();
|
189 |
+
else if ( $this->did_footer )
|
190 |
+
$this->output_footer();
|
191 |
+
|
192 |
+
}
|
193 |
+
|
194 |
+
public function action_init() {
|
195 |
+
|
196 |
+
global $wp_locale;
|
197 |
+
|
198 |
+
load_plugin_textdomain( 'query-monitor', false, dirname( $this->plugin_base() ) . '/languages' );
|
199 |
+
|
200 |
+
if ( !$this->show_query_monitor() )
|
201 |
+
return;
|
202 |
+
|
203 |
+
if ( QM_Util::is_ajax() )
|
204 |
+
ob_start();
|
205 |
+
|
206 |
+
if ( !defined( 'DONOTCACHEPAGE' ) )
|
207 |
+
define( 'DONOTCACHEPAGE', 1 );
|
208 |
+
|
209 |
+
wp_enqueue_style(
|
210 |
+
'query-monitor',
|
211 |
+
$this->plugin_url( 'assets/query-monitor.css' ),
|
212 |
+
null,
|
213 |
+
$this->plugin_ver( 'assets/query-monitor.css' )
|
214 |
+
);
|
215 |
+
wp_enqueue_script(
|
216 |
+
'query-monitor',
|
217 |
+
$this->plugin_url( 'assets/query-monitor.js' ),
|
218 |
+
array( 'jquery' ),
|
219 |
+
$this->plugin_ver( 'assets/query-monitor.js' ),
|
220 |
+
true
|
221 |
+
);
|
222 |
+
wp_localize_script(
|
223 |
+
'query-monitor',
|
224 |
+
'qm_locale',
|
225 |
+
(array) $wp_locale
|
226 |
+
);
|
227 |
+
|
228 |
+
}
|
229 |
+
|
230 |
+
public function output_footer() {
|
231 |
+
|
232 |
+
if ( !$this->show_query_monitor() )
|
233 |
+
return;
|
234 |
+
|
235 |
+
# Flush the output buffer to avoid crashes
|
236 |
+
if ( !is_feed() ) {
|
237 |
+
while ( ob_get_length() )
|
238 |
+
ob_flush();
|
239 |
+
}
|
240 |
+
|
241 |
+
foreach ( $this->get_components() as $component )
|
242 |
+
$component->process();
|
243 |
+
|
244 |
+
if ( !function_exists( 'is_admin_bar_showing' ) or !is_admin_bar_showing() )
|
245 |
+
$class = 'qm-show';
|
246 |
+
else
|
247 |
+
$class = '';
|
248 |
+
|
249 |
+
$qm = array(
|
250 |
+
'menu' => $this->js_admin_bar_menu(),
|
251 |
+
'ajax_errors' => array() # @TODO move this into the php_errors component
|
252 |
+
);
|
253 |
+
|
254 |
+
echo '<script type="text/javascript">' . "\n\n";
|
255 |
+
echo 'var qm = ' . json_encode( $qm ) . ';' . "\n\n";
|
256 |
+
echo '</script>' . "\n\n";
|
257 |
+
|
258 |
+
echo '<div id="qm" class="' . $class . '">';
|
259 |
+
echo '<div id="qm-wrapper">';
|
260 |
+
echo '<p>' . __( 'Query Monitor', 'query-monitor' ) . '</p>';
|
261 |
+
|
262 |
+
foreach ( $this->get_components() as $component ) {
|
263 |
+
$component->output_html( array(
|
264 |
+
'id' => $component->id()
|
265 |
+
), $component->get_data() );
|
266 |
+
}
|
267 |
+
|
268 |
+
echo '</div>';
|
269 |
+
echo '</div>';
|
270 |
+
|
271 |
+
}
|
272 |
+
|
273 |
+
public function output_ajax() {
|
274 |
+
|
275 |
+
# if the headers have already been sent then we can't do anything about it
|
276 |
+
if ( headers_sent() )
|
277 |
+
return;
|
278 |
+
|
279 |
+
if ( !$this->show_query_monitor() )
|
280 |
+
return;
|
281 |
+
|
282 |
+
foreach ( $this->get_components() as $component )
|
283 |
+
$component->process();
|
284 |
+
|
285 |
+
foreach ( $this->get_components() as $component ) {
|
286 |
+
$component->output_headers( array(
|
287 |
+
'id' => $component->id()
|
288 |
+
), $component->get_data() );
|
289 |
+
}
|
290 |
+
|
291 |
+
# flush once, because we're nice
|
292 |
+
if ( ob_get_length() )
|
293 |
+
ob_flush();
|
294 |
+
|
295 |
+
}
|
296 |
+
|
297 |
+
public function filter_active_plugins( array $plugins ) {
|
298 |
+
|
299 |
+
$f = preg_quote( basename( __FILE__ ) );
|
300 |
+
|
301 |
+
return array_merge(
|
302 |
+
preg_grep( '/' . $f . '$/', $plugins ),
|
303 |
+
preg_grep( '/' . $f . '$/', $plugins, PREG_GREP_INVERT )
|
304 |
+
);
|
305 |
+
|
306 |
+
}
|
307 |
+
|
308 |
+
public function filter_active_sitewide_plugins( array $plugins ) {
|
309 |
+
|
310 |
+
$f = plugin_basename( __FILE__ );
|
311 |
+
|
312 |
+
if ( isset( $plugins[$f] ) ) {
|
313 |
+
|
314 |
+
unset( $plugins[$f] );
|
315 |
+
|
316 |
+
return array_merge( array(
|
317 |
+
$f => time(),
|
318 |
+
), $plugins );
|
319 |
+
|
320 |
+
} else {
|
321 |
+
return $plugins;
|
322 |
+
}
|
323 |
+
|
324 |
+
}
|
325 |
+
|
326 |
+
}
|
327 |
+
|
328 |
+
$GLOBALS['querymonitor'] = new QueryMonitor( __FILE__ );
|
readme.txt
ADDED
@@ -0,0 +1,291 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== Query Monitor ===
|
2 |
+
Contributors: johnbillion
|
3 |
+
Tags: debug, debugging, development, developer, performance, profiler, profiling, queries
|
4 |
+
Requires at least: 3.5
|
5 |
+
Tested up to: 3.7
|
6 |
+
Stable tag: 2.5.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 unique features not yet seen in other debugging plugins, including automatic AJAX debugging and the ability to narrow down things by plugin or theme.
|
14 |
+
|
15 |
+
For complete information, please see [Query Monitor's GitHub repo](https://github.com/johnbillion/QueryMonitor).
|
16 |
+
|
17 |
+
Here's an overview of what's shown:
|
18 |
+
|
19 |
+
= Database Queries =
|
20 |
+
|
21 |
+
* Shows all database queries performed on the current page
|
22 |
+
* Shows **affected rows** and time for all queries
|
23 |
+
* Show notifications for **slow 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
|
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. Query Monitor can easily tell you if your "premium" theme is doing a premium number of database queries.
|
31 |
+
|
32 |
+
= Hooks =
|
33 |
+
|
34 |
+
* Shows all hooks fired on the current page, along with hooked actions and their priorities
|
35 |
+
* Filter hooks by **part of their name**
|
36 |
+
* Filter actions by **component** (WordPress core, Plugin X, Plugin Y, theme)
|
37 |
+
|
38 |
+
= Theme =
|
39 |
+
|
40 |
+
* Shows the **template filename** for the current page
|
41 |
+
* Shows the available **body classes** for the current page
|
42 |
+
* Shows the active theme name
|
43 |
+
|
44 |
+
= PHP Errors =
|
45 |
+
|
46 |
+
* PHP errors (warnings, notices and stricts) are presented nicely along with their component and call stack
|
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)
|
53 |
+
* Shows the response code, call stack, transport, timeout, and time taken
|
54 |
+
* Highlights **erroneous responses**, such as failed requests and anything without a `200` response code
|
55 |
+
|
56 |
+
= Redirects =
|
57 |
+
|
58 |
+
* Whenever a redirect occurs, Query Monitor adds an `X-QM-Redirect` HTTP header containing the call stack, so you can use your favourite HTTP inspector to easily trace where a redirect has come from
|
59 |
+
|
60 |
+
= AJAX =
|
61 |
+
|
62 |
+
The response from any jQuery AJAX request on the page will contain various debugging information in its header that gets output to the developer console. **No hooking required**.
|
63 |
+
|
64 |
+
AJAX debugging is in its early stages. Currently it only includes PHP errors (warnings, notices and stricts), but this will be built upon in future versions.
|
65 |
+
|
66 |
+
= Admin Screen =
|
67 |
+
|
68 |
+
Hands up who can remember the correct names for the filters and hooks for custom admin screen columns?
|
69 |
+
|
70 |
+
* Shows the correct names for **custom column hooks and filters** on all admin screens that have a listing table
|
71 |
+
* Shows the state of `get_current_screen()` and a few variables
|
72 |
+
|
73 |
+
= Environment Information =
|
74 |
+
|
75 |
+
* Shows **various PHP information** such as memory limit and error reporting levels
|
76 |
+
* Highlights the fact when any of these are overridden at runtime
|
77 |
+
* Shows **various MySQL information**, including caching and performance related configuration
|
78 |
+
* Highlights the fact when any performance related configurations are not optimal
|
79 |
+
* Shows various details about **WordPress** and the **web server**
|
80 |
+
* Shows version numbers for everything
|
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
|
88 |
+
* You can set an authentication cookie which allows you to view Query Monitor output when you're not logged in (or if you're logged in as a non-administrator). See the bottom of Query Monitor's output for details
|
89 |
+
|
90 |
+
== Installation ==
|
91 |
+
|
92 |
+
You can install this plugin directly from your WordPress dashboard:
|
93 |
+
|
94 |
+
1. Go to the *Plugins* menu and click *Add New*.
|
95 |
+
2. Search for *Query Monitor*.
|
96 |
+
3. Click *Install Now* next to the Query Monitor plugin.
|
97 |
+
4. Activate the plugin.
|
98 |
+
|
99 |
+
Alternatively, see the guide to [Manually Installing Plugins](http://codex.wordpress.org/Managing_Plugins#Manual_Plugin_Installation).
|
100 |
+
|
101 |
+
== Screenshots ==
|
102 |
+
|
103 |
+
1. An example of Query Monitor's output
|
104 |
+
|
105 |
+
== Frequently Asked Questions ==
|
106 |
+
|
107 |
+
= There's nothing here =
|
108 |
+
|
109 |
+
I know!
|
110 |
+
|
111 |
+
== Changelog ==
|
112 |
+
|
113 |
+
= 2.5.2 =
|
114 |
+
* Prevent uncaught exceptions with static method actions
|
115 |
+
* Misc formatting tweaks
|
116 |
+
|
117 |
+
= 2.5.1 =
|
118 |
+
* Un-break query filtering
|
119 |
+
* Performance improvements
|
120 |
+
|
121 |
+
= 2.5 =
|
122 |
+
* Display the component for HTTP requests, transients, PHP errors, and hook actions
|
123 |
+
* Improved visual appearance and layout
|
124 |
+
* Add an action component filter to the Hooks panel
|
125 |
+
* Log errors returned in the `pre_http_request` filter
|
126 |
+
* `QM_DB_LIMIT` is now a soft limit
|
127 |
+
* Performance improvements
|
128 |
+
|
129 |
+
= 2.4.2 =
|
130 |
+
* Add a hook name filter to the Hooks panel
|
131 |
+
* Update db.php to match latest wp-db.php
|
132 |
+
* Avoid fatal error if the plugin is manually deleted
|
133 |
+
* Add the new `is_main_network()` conditional
|
134 |
+
* Lots more tweaks
|
135 |
+
|
136 |
+
= 2.4.1 =
|
137 |
+
* Un-break all the things
|
138 |
+
|
139 |
+
= 2.4 =
|
140 |
+
* New Redirect component
|
141 |
+
* Add support for strict errors
|
142 |
+
* Display the call stack for HTTP requests
|
143 |
+
* Display the call stack for transients
|
144 |
+
* Remove pre-3.0 back-compat code
|
145 |
+
* Many other bugfixes and tweaks
|
146 |
+
|
147 |
+
= 2.3.1 =
|
148 |
+
* Compat with Xdebug
|
149 |
+
* Display the call stack for PHP errors
|
150 |
+
|
151 |
+
= 2.3 =
|
152 |
+
* Introduce AJAX debugging (just PHP errors for now)
|
153 |
+
* Visual refresh
|
154 |
+
* Add theme and stylesheet into to the Theme panel
|
155 |
+
|
156 |
+
= 2.2.8 =
|
157 |
+
* Add error reporting to the Environment panel
|
158 |
+
|
159 |
+
= 2.2.7 =
|
160 |
+
* Don't output QM in the theme customizer
|
161 |
+
|
162 |
+
= 2.2.6 =
|
163 |
+
* Add the database query time to the admin toolbar
|
164 |
+
* Various trace and JavaScript errors
|
165 |
+
|
166 |
+
= 2.2.5 =
|
167 |
+
* Load QM before other plugins
|
168 |
+
* Show QM output on the log in screen
|
169 |
+
|
170 |
+
= 2.2.4 =
|
171 |
+
* Add filtering to the qyer panel
|
172 |
+
|
173 |
+
= 2.2.3 =
|
174 |
+
* Show component information indicating whether a plugin, theme or core was responsible for each database query
|
175 |
+
* New Query Component panel showing components ordered by total query time
|
176 |
+
|
177 |
+
= 2.2.2 =
|
178 |
+
* Show memory usage as a percentage of the memory limit
|
179 |
+
* Show page generation time as percentage of the limit, if it's high
|
180 |
+
* Show a few bits of server information in the Environment panel
|
181 |
+
* Log PHP settings as early as possible and highlight when the values have been altered at runtime
|
182 |
+
|
183 |
+
= 2.2.1 =
|
184 |
+
* A few formatting and layout tweaks
|
185 |
+
|
186 |
+
= 2.2 =
|
187 |
+
* Breakdown queries by type in the Overview and Query Functions panels
|
188 |
+
* Show the HTTP transport order of preference in the HTTP panel
|
189 |
+
* Highlight database errors and slow database queries in their own panels
|
190 |
+
* Add a few PHP enviroment variables to the Environment panel (more to come)
|
191 |
+
|
192 |
+
= 2.1.8 =
|
193 |
+
* Change i18n text domain
|
194 |
+
* Hide Authentication panel for non-JS
|
195 |
+
* Show database info in Overview panel
|
196 |
+
|
197 |
+
= 2.1.7 =
|
198 |
+
* Full WordPress 3.4 compatibility
|
199 |
+
|
200 |
+
= 2.1.6 =
|
201 |
+
* Small tweaks to conditionals and HTTP components
|
202 |
+
* Allow filtering of ignore_class, ignore_func and show_arg on QM and QM DB
|
203 |
+
|
204 |
+
= 2.1.5 =
|
205 |
+
* Tweak a few conditional outputs
|
206 |
+
* Full support for all WPDB instances
|
207 |
+
* Tweak query var output
|
208 |
+
* Initial code for data logging before redirects (incomplete)
|
209 |
+
|
210 |
+
= 2.1.4 =
|
211 |
+
* Add full support for multiple DB instances to the Environment component
|
212 |
+
* Improve PHP error function stack
|
213 |
+
|
214 |
+
= 2.1.3 =
|
215 |
+
* Fix display of wp_admin_bar instantiated queries
|
216 |
+
* Fix function trace for HTTP calls and transients
|
217 |
+
|
218 |
+
= 2.1.2 =
|
219 |
+
* Lots more behind the scenes improvements
|
220 |
+
* Better future-proof CSS
|
221 |
+
* Complete separation of data/presentation in db_queries
|
222 |
+
* Complete support for multiple database connections
|
223 |
+
|
224 |
+
= 2.1.1 =
|
225 |
+
* Lots of behind the scenes improvements
|
226 |
+
* More separation of data from presentation
|
227 |
+
* Fewer cross-component dependencies
|
228 |
+
* Nicer way of doing menu items, classes & title
|
229 |
+
|
230 |
+
= 2.1 =
|
231 |
+
* Let's split everything up into components. Lots of optimisations to come.
|
232 |
+
|
233 |
+
= 2.0.3 =
|
234 |
+
* Localisation improvements
|
235 |
+
|
236 |
+
= 2.0.2 =
|
237 |
+
* Admin bar tweaks for WordPress 3.3
|
238 |
+
* Add some missing l10n
|
239 |
+
* Prevent some PHP notices
|
240 |
+
|
241 |
+
= 2.0.1 =
|
242 |
+
* Just a few rearrangements
|
243 |
+
|
244 |
+
= 2.0 =
|
245 |
+
* Show warnings next to MySQL variables with sub-optimal values
|
246 |
+
|
247 |
+
= 1.9.3 =
|
248 |
+
* Fix list of non-default query vars
|
249 |
+
* Fix list of admin screen column names in 3.3
|
250 |
+
* Lots of other misc tweaks
|
251 |
+
* Add RTL support
|
252 |
+
|
253 |
+
= 1.9.2 =
|
254 |
+
* Lots of interface improvements
|
255 |
+
* Show counts for transients, HTTP requests and custom query vars in the admin menu
|
256 |
+
* Add backtrace to PHP error output
|
257 |
+
* Hide repeated identical PHP errors
|
258 |
+
* Filter out calls to _deprecated_*() and trigger_error() in backtraces
|
259 |
+
* Show do_action_ref_array() and apply_filters_ref_array() parameter in backtraces
|
260 |
+
* Remove the 'component' code
|
261 |
+
* Remove the object cache output
|
262 |
+
* Add a 'qm_template' filter so themes that do crazy things can report the correct template file
|
263 |
+
|
264 |
+
= 1.9.1 =
|
265 |
+
* Display all custom column filter names on admin screens that contain columns
|
266 |
+
|
267 |
+
= 1.9 =
|
268 |
+
* Display more accurate $current_screen values
|
269 |
+
* Display a warning message about bug with $typenow and $current_screen values
|
270 |
+
* Improve PHP error backtrace
|
271 |
+
|
272 |
+
= 1.8 =
|
273 |
+
* Introduce a 'view_query_monitor' capability for finer grained permissions control
|
274 |
+
|
275 |
+
= 1.7.11 =
|
276 |
+
* List body classes with the template output
|
277 |
+
* Display calling function in PHP warnings and notices
|
278 |
+
* Fix admin bar CSS when displaying notices
|
279 |
+
* Remove pointless non-existant filter code
|
280 |
+
|
281 |
+
= 1.7.10.1 =
|
282 |
+
* Fix a formatting error in the transient table
|
283 |
+
|
284 |
+
= 1.7.10 =
|
285 |
+
* Tweaks to counts, HTTP output and transient output
|
286 |
+
* Upgrade routine which adds a symlink to db.php in wp-content/db.php
|
287 |
+
|
288 |
+
= 1.7.9 =
|
289 |
+
* PHP warning and notice handling
|
290 |
+
* Add some new template conditionals
|
291 |
+
* Tweaks to counts, HTTP output and transient output
|
wp-content/db.php
ADDED
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Plugin Name: Query Monitor
|
4 |
+
|
5 |
+
*********************************************************************
|
6 |
+
|
7 |
+
Ensure this file is symlinked to your wp-content directory to provide
|
8 |
+
additional database query information in Query Monitor's output.
|
9 |
+
|
10 |
+
*********************************************************************
|
11 |
+
|
12 |
+
Copyright 2013 John Blackbourn
|
13 |
+
|
14 |
+
This program is free software; you can redistribute it and/or modify
|
15 |
+
it under the terms of the GNU General Public License as published by
|
16 |
+
the Free Software Foundation; either version 2 of the License, or
|
17 |
+
(at your option) any later version.
|
18 |
+
|
19 |
+
This program is distributed in the hope that it will be useful,
|
20 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
21 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
22 |
+
GNU General Public License for more details.
|
23 |
+
|
24 |
+
*/
|
25 |
+
|
26 |
+
defined( 'ABSPATH' ) or die();
|
27 |
+
|
28 |
+
if ( ! is_readable( $autoloader = dirname( __FILE__ ) . '/../autoloader.php' ) )
|
29 |
+
return;
|
30 |
+
|
31 |
+
include_once $autoloader;
|
32 |
+
|
33 |
+
if ( !defined( 'SAVEQUERIES' ) )
|
34 |
+
define( 'SAVEQUERIES', true );
|
35 |
+
|
36 |
+
class QueryMonitorDB extends wpdb {
|
37 |
+
|
38 |
+
public $qm_php_vars = array(
|
39 |
+
'max_execution_time' => null,
|
40 |
+
'memory_limit' => null,
|
41 |
+
'upload_max_filesize' => null,
|
42 |
+
'post_max_size' => null,
|
43 |
+
'display_errors' => null,
|
44 |
+
'log_errors' => null,
|
45 |
+
);
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Class constructor
|
49 |
+
*/
|
50 |
+
function __construct( $dbuser, $dbpassword, $dbname, $dbhost ) {
|
51 |
+
|
52 |
+
foreach ( $this->qm_php_vars as $setting => &$val )
|
53 |
+
$val = ini_get( $setting );
|
54 |
+
|
55 |
+
parent::__construct( $dbuser, $dbpassword, $dbname, $dbhost );
|
56 |
+
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Perform a MySQL database query, using current database connection.
|
61 |
+
*
|
62 |
+
* More information can be found on the codex page.
|
63 |
+
*
|
64 |
+
* @since 0.71
|
65 |
+
*
|
66 |
+
* @param string $query Database query
|
67 |
+
* @return int|false Number of rows affected/selected or false on error
|
68 |
+
*/
|
69 |
+
function query( $query ) {
|
70 |
+
if ( ! $this->ready )
|
71 |
+
return false;
|
72 |
+
|
73 |
+
if ( $this->show_errors and class_exists( 'QM_Component_DB_Queries' ) )
|
74 |
+
$this->hide_errors();
|
75 |
+
|
76 |
+
// some queries are made before the plugins have been loaded, and thus cannot be filtered with this method
|
77 |
+
$query = apply_filters( 'query', $query );
|
78 |
+
|
79 |
+
$return_val = 0;
|
80 |
+
$this->flush();
|
81 |
+
|
82 |
+
// Log how the function was called
|
83 |
+
$this->func_call = "\$db->query(\"$query\")";
|
84 |
+
|
85 |
+
// Keep track of the last query for debug..
|
86 |
+
$this->last_query = $query;
|
87 |
+
|
88 |
+
if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES )
|
89 |
+
$this->timer_start();
|
90 |
+
|
91 |
+
$this->result = @mysql_query( $query, $this->dbh );
|
92 |
+
$this->num_queries++;
|
93 |
+
|
94 |
+
if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
|
95 |
+
$trace = new QM_Backtrace;
|
96 |
+
$q = array(
|
97 |
+
'sql' => $query,
|
98 |
+
'ltime' => $this->timer_stop(),
|
99 |
+
'stack' => implode( ', ', array_reverse( $trace->get_stack() ) ),
|
100 |
+
'trace' => $trace,
|
101 |
+
'result' => null,
|
102 |
+
);
|
103 |
+
# Numeric indices are for compatibility for anything else using saved queries
|
104 |
+
$q[0] = $q['sql'];
|
105 |
+
$q[1] = $q['ltime'];
|
106 |
+
$q[2] = $q['stack'];
|
107 |
+
$this->queries[$this->num_queries] = $q;
|
108 |
+
}
|
109 |
+
|
110 |
+
// If there is an error then take note of it..
|
111 |
+
if ( $this->last_error = mysql_error( $this->dbh ) ) {
|
112 |
+
if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES )
|
113 |
+
$this->queries[$this->num_queries]['result'] = new WP_Error( 'qmdb', $this->last_error );
|
114 |
+
// Clear insert_id on a subsequent failed insert.
|
115 |
+
if ( $this->insert_id && preg_match( '/^\s*(insert|replace)\s/i', $query ) )
|
116 |
+
$this->insert_id = 0;
|
117 |
+
|
118 |
+
$this->print_error();
|
119 |
+
return false;
|
120 |
+
}
|
121 |
+
|
122 |
+
if ( preg_match( '/^\s*(create|alter|truncate|drop)\s/i', $query ) ) {
|
123 |
+
$return_val = $this->result;
|
124 |
+
} elseif ( preg_match( '/^\s*(insert|delete|update|replace)\s/i', $query ) ) {
|
125 |
+
$this->rows_affected = mysql_affected_rows( $this->dbh );
|
126 |
+
// Take note of the insert_id
|
127 |
+
if ( preg_match( '/^\s*(insert|replace)\s/i', $query ) ) {
|
128 |
+
$this->insert_id = mysql_insert_id($this->dbh);
|
129 |
+
}
|
130 |
+
// Return number of rows affected
|
131 |
+
$return_val = $this->rows_affected;
|
132 |
+
} else {
|
133 |
+
$num_rows = 0;
|
134 |
+
while ( $row = @mysql_fetch_object( $this->result ) ) {
|
135 |
+
$this->last_result[$num_rows] = $row;
|
136 |
+
$num_rows++;
|
137 |
+
}
|
138 |
+
|
139 |
+
// Log number of rows the query returned
|
140 |
+
// and return number of rows selected
|
141 |
+
$this->num_rows = $num_rows;
|
142 |
+
$return_val = $num_rows;
|
143 |
+
}
|
144 |
+
|
145 |
+
if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES )
|
146 |
+
$this->queries[$this->num_queries]['result'] = $return_val;
|
147 |
+
|
148 |
+
return $return_val;
|
149 |
+
}
|
150 |
+
|
151 |
+
}
|
152 |
+
|
153 |
+
$wpdb = new QueryMonitorDB( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST );
|