Initial commit

This commit is contained in:
Felix Förtsch
2020-10-20 14:39:50 +02:00
commit 648ded8896
1225 changed files with 216511 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
[*]
indent_style = tab
trim_trailing_whitespace = true

View File

@@ -0,0 +1,25 @@
<?php
/**
* Abstract data collector.
*
* @package query-monitor-extend
*/
abstract class QMX_Collector extends QM_Collector {
protected static $hide_qmx = null;
public static function hide_qmx() {
if ( null === self::$hide_qmx ) {
self::$hide_qmx = ( defined( 'QMX_HIDE_SELF' ) && QMX_HIDE_SELF );
}
return self::$hide_qmx;
}
public function filter_remove_qmx( array $item ) {
$component = $item['trace']->get_component();
return ( 'query-monitor-extend' !== $component->context );
}
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* Container for data collectors.
*
* @package query-monitor-extend
*/
class QMX_Collectors extends QM_Collectors {
private $items = array();
public static function add( QM_Collector $collector ) {
$collectors = self::init();
QM_Collectors::add( $collector );
$collectors->items[$collector->id] = QM_Collectors::get( $collector->id );
}
public static function init() {
static $instance;
if ( ! $instance ) {
$instance = new self;
}
return $instance;
}
}

View File

@@ -0,0 +1,10 @@
<?php
/**
* Abstract output handler.
*
* @package query-monitor-extend
*/
abstract class QMX_Output extends QM_Output {
}

View File

@@ -0,0 +1,10 @@
<?php
/**
* Abstract plugin wrapper.
*
* @package query-monitor-extend
*/
class QMX_Plugin extends QM_Plugin {
}

View File

@@ -0,0 +1,168 @@
<?php
/**
* The main Query Monitor Extend plugin class.
*
* @package query-monitor-extend
*/
class QueryMonitorExtend extends QMX_Plugin {
protected function __construct( $file ) {
if ( self::is_debugging() )
add_action( 'init', function() { $this->_tests(); } );
add_action( 'plugins_loaded', array( &$this, 'action__plugins_loaded' ) );
add_action( 'shutdown', array( &$this, 'action__shutdown' ), -1 );
add_filter( 'plugin_row_meta', array( &$this, 'filter__plugin_row_meta' ), 10, 2 );
add_filter( 'qm/outputter/html', array( &$this, 'filter__qm_outputter_html' ) );
add_filter( 'qm/collect/conditionals', array( &$this, 'filter__qm_collect_conditionals' ) );
# Parent setup:
parent::__construct( $file );
$collectors = array();
foreach ( glob( $this->plugin_path( 'collectors/*.php' ) ) as $file ) {
$key = basename( $file, '.php' );
$collectors[$key] = $file;
}
foreach ( apply_filters( 'qmx/built-in-collectors', $collectors ) as $file ) {
include $file;
}
}
function action__plugins_loaded() {
# Register additional collectors:
foreach ( apply_filters( 'qmx/collectors', array(), $this ) as $collector ) {
QMX_Collectors::add( $collector );
}
}
function action__shutdown() {
global $qm_dir;
require_once $qm_dir . '/output/Html.php';
require_once $this->plugin_path( 'output/Html.php' );
foreach ( glob( $this->plugin_path( 'output/html/*.php' ) ) as $file ) {
require_once $file;
}
}
function filter__plugin_row_meta( $meta, $file ) {
if ( 'query-monitor-extend/query-monitor-extend.php' !== $file )
return $meta;
$first = array_shift( $meta );
array_unshift(
$meta,
$first,
'Tested up to <a href="https://wordpress.org/plugins/query-monitor/" target="_blank" rel="noopener">Query Monitor</a> <a href="https://github.com/johnbillion/query-monitor/releases/tag/3.1.1" target="_blank" rel="noopener">3.1.1</a>'
);
return $meta;
}
function filter__qm_outputter_html( $outputters ) {
return apply_filters( 'qmx/outputter/html', array() );
}
function filter__qm_collect_conditionals( $conds ) {
$conds = array_merge( $conds, array(
'is_cart',
'is_checkout',
'is_shop',
'is_woocommerce',
'is_product_category',
'is_product_tag',
'is_product',
'is_account_page',
'is_wc_endpoint_url',
'has_post_thumbnail',
) );
sort( $conds );
return $conds;
}
public static function init( $file = null ) {
static $instance = null;
if ( ! $instance ) {
$instance = new QueryMonitorExtend( $file );
}
return $instance;
}
public static function is_debugging() {
return defined( 'QMX_DEBUG' ) && QMX_DEBUG;
}
protected function _tests() {
if (
defined( 'DOING_AJAX' )
&& DOING_AJAX
)
return;
if ( 1 ) {
global $wpdb;
$wpdb->query( 'SELECT * FROM `not_a_table`' );
$wpdb->query( 'SELECT SLEEP( ' . ( QM_DB_EXPENSIVE + 0.01 ) . ' )' );
}
if ( 1 ) {
wp_remote_get( 'http://not-a-server.local', array( 'timeout' => '0.1' ) );
wp_remote_get( 'https://httpstat.us/400' );
}
if ( 1 ) trigger_error( 'Notice' );
if ( 1 ) trigger_error( 'Warning', E_USER_WARNING );
if ( 1 ) trigger_error( 'Deprecated', E_USER_DEPRECATED );
if ( 1 )
wp_enqueue_style( 'does-not-exist', 'https://localhost/no-stylesheet.css', array( 'not-dependency' ) );
if ( 1 )
qm_dump( array(
'one' => range( 1, 9 ),
'two' => 2,
'three' => array( 'a', 'b', 'c', 'd', 'e', ),
'four' => array(
1 => 'two',
3 => 'four',
),
'five' => true,
'six' => null,
), 'Test' );
if ( 1 )
qm_dump( ( object ) array(
'one' => range( 5, 13 ),
'two' => array( 'a', 'b', 'c', 'd' ),
'three' => ( object ) array(
'a' => 'alpha',
'b' => 'beta',
'c' => 'charlie',
'd' => 'delta',
),
) );
}
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* Constants collector.
*
* @package query-monitor-extend
*/
class QMX_Collector_Constants extends QMX_Collector {
public $id = 'constants';
public function name() {
return __( 'Constants', 'query-monitor-extend' );
}
public function process() {
$constants = get_defined_constants( true );
$this->data['constants'] = $constants['user'];
}
}
function register_qmx_collector_constants( array $collectors, QueryMonitorExtend $qmx ) {
$collectors['constants'] = new QMX_Collector_Constants;
return $collectors;
}
add_filter( 'qmx/collectors', 'register_qmx_collector_constants', 10, 2 );

View File

@@ -0,0 +1,41 @@
<?php
/**
* Files collector.
*
* @package query-monitor-extend
*/
class QMX_Collector_Files extends QMX_Collector {
public $id = 'files';
public function name() {
return __( 'Files', 'query-monitor-extend' );
}
public function process() {
$php_errors = QM_Collectors::get( 'php_errors' )->get_data();
$files_with_errors = array();
if ( !empty( $php_errors['errors'] ) )
foreach ( $php_errors['errors'] as $type => $errors )
foreach ( $errors as $error )
$files_with_errors[$error['file']] = 1;
foreach ( get_included_files() as $i => $filepath )
$this->data['files'][] = array(
'path' => $filepath,
'component' => QM_Util::get_file_component( $filepath ),
'has_error' => array_key_exists( $filepath, $files_with_errors ),
);
}
}
function register_qmx_collector_files( array $collectors, QueryMonitorExtend $qmx ) {
$collectors['files'] = new QMX_Collector_Files;
return $collectors;
}
add_filter( 'qmx/collectors', 'register_qmx_collector_files', 10, 2 );

View File

@@ -0,0 +1,165 @@
<?php
/**
* Heartbeat collector.
*
* @package query-monitor-extend
*/
class QMX_Collector_Heartbeat extends QMX_Collector {
public $id = 'heartbeat';
function __construct() {
parent::__construct();
if ( $this->qm_no_jquery() )
return;
add_action( 'wp_enqueue_scripts', array( &$this, 'add_inline_script' ) );
add_action( 'admin_enqueue_scripts', array( &$this, 'add_inline_script' ) );
}
public function add_inline_script() {
wp_add_inline_script( 'heartbeat', $this->_inlineScript_heartbeat() );
}
public function _inlineScript_heartbeat() {
ob_start();
?>
var qmx_heartbeat = {
_beat: null,
_beats: [],
_start: 0,
_table: null,
_tab: null,
_table_ready: false,
_prev_dub: 0,
init: function() {
var that = this;
var d = new Date();
this._start = d.getTime();
jQuery( document ).on( 'heartbeat-send', function() {
var d = new Date();
var lub = d.getTime();
var count = ( that._beats.find( 'tr' ).length + 1 );
if (
2 == count
&& that._beats.find( 'tr' ).hasClass( 'listening' )
) {
that._beats.html( '' );
count = 1;
}
if ( !that._table_ready ) {
that._beat = { lub: lub };
return;
}
that.add_table_row( that.get_table_row(
count,
lub,
'',
(
0 == that._prev_dub
? '-'
: ( lub - that._prev_dub )
),
'-'
) );
that.update_tab( count );
that._beat = that._beats.find( 'tr:last-child' );
} );
jQuery( document ).on( 'heartbeat-tick', function() {
var d = new Date();
var dub = d.getTime();
if ( !that._table_ready ) {
that._beat.dub = dub;
that['_beats'].push( that._beat );
that._beat = null;
return;
}
var dub_secs = ( dub - that._start ) / 1000;
var duration = ( ( ( dub - that._start ) / 1000 ) - parseFloat( that._beat.find( 'td.lub' ).text() ) );
that._beat.find( 'td.dub' ).html( dub_secs.toFixed( 3 ) );
that._beat.find( 'td.dur' ).html( duration.toFixed( 3 ) );
that._prev_dub = dub;
} );
},
populate_table: function() {
this._table_ready = true;
this._table = jQuery( <?php echo json_encode( '#' . esc_attr( $this->id() ) . ' > table' ) ?> );
this._beats = this._table.find( 'tbody' );
},
add_table_row: function( tr ) {
this._table.find( 'tbody:last-child' ).append( tr );
},
get_table_row: function( index, lub, dub, since_last, duration ) {
var lub_diff = ( lub - this._start ) / 1000;
var dub_diff = ( dub - this._start ) / 1000;
var duration_secs = duration / 1000;
var since_last_secs = '-' != since_last ? since_last / 1000 : '-';
since_last_secs = '-' != since_last_secs ? since_last_secs.toFixed( 3 ) : '-';
return '<tr' +
(
1 == ( index % 2 )
? ' class="qm-odd"'
: ''
) +
'>' +
'<td class="qm-num">' + index + '</td>' +
'<td class="qm-num lub">' + lub_diff.toFixed( 3 ) + '</td>' +
'<td class="qm-num dub">' + dub_diff.toFixed( 3 ) + '</td>' +
'<td class="qm-num since">' + since_last_secs + '</td>' +
'<td class="qm-num dur">' + duration_secs.toFixed( 3 ) + '</td>' +
'</tr>';
},
update_tab: function( count ) {
this._tab = jQuery( '#qm-panel-menu button[data-qm-href=<?php echo json_encode( '#' . esc_attr( $this->id() ) ) ?>]' );
this._tab.html( 'Heartbeats (' + count + ')' );
}
};
qmx_heartbeat.init();
<?php
return ob_get_clean();
}
public function name() {
return __( 'Heartbeat', 'query-monitor-extend' );
}
public function process() {
}
public function qm_no_jquery() {
return defined( 'QM_NO_JQUERY' ) && QM_NO_JQUERY;
}
}
function register_qmx_collector_heartbeat( array $collectors, QueryMonitorExtend $qmx ) {
$collectors['heartbeat'] = new QMX_Collector_Heartbeat;
return $collectors;
}
add_filter( 'qmx/collectors', 'register_qmx_collector_heartbeat', 10, 2 );

View File

@@ -0,0 +1,195 @@
<?php
/**
* Image sizes collector.
*
* @package query-monitor-extend
*/
class QMX_Collector_Image_Sizes extends QMX_Collector {
public $id = 'image_sizes';
public function __construct() {
$this->data['sizes'] = array(
'thumbnail' => array(
'width' => intval( get_option( 'thumbnail_size_w' ) ),
'height' => intval( get_option( 'thumbnail_size_h' ) ),
'source' => 'native',
'crop' => true,
'num' => 1,
),
'medium' => array(
'width' => intval( get_option( 'medium_size_w' ) ),
'height' => intval( get_option( 'medium_size_h' ) ),
'source' => 'native',
'crop' => false,
'num' => 2,
),
'medium_large' => array(
'width' => intval( get_option( 'medium_large_size_w' ) ),
'height' => intval( get_option( 'medium_large_size_h' ) ),
'source' => 'native',
'crop' => false,
'num' => 3,
),
'large' => array(
'width' => intval( get_option( 'large_size_w' ) ),
'height' => intval( get_option( 'large_size_h' ) ),
'source' => 'native',
'crop' => false,
'num' => 4,
),
);
add_action( 'plugins_loaded', array( &$this, 'action__plugins_loaded' ) );
add_action( 'after_setup_theme', array( &$this, 'action__after_setup_theme' ) );
add_action( 'wp_enqueue_scripts', array( &$this, 'add_inline_script' ), -998 );
add_action( 'admin_enqueue_scripts', array( &$this, 'add_inline_script' ), -998 );
add_action( 'login_enqueue_scripts', array( &$this, 'add_inline_script' ), -998 );
add_action( 'enqueue_embed_scripts', array( &$this, 'add_inline_script' ), -998 );
}
function action__plugins_loaded() {
if ( 'plugins_loaded' !== current_action() )
return;
$this->_process_added_image_sizes( 'plugin' );
}
function action__after_setup_theme() {
if ( 'after_setup_theme' !== current_action() )
return;
$this->_process_added_image_sizes( 'theme' );
}
protected function _process_added_image_sizes( $source = 'unknown' ) {
global $_wp_additional_image_sizes;
$num = count( $this->data['sizes'] );
if (
is_array( $_wp_additional_image_sizes )
&& !empty( $_wp_additional_image_sizes )
)
foreach ( $_wp_additional_image_sizes as $id => $size )
if ( !array_key_exists( $id, $this->data['sizes'] ) )
$this->data['sizes'][$id] = array_merge(
array(
'num' => ++$num,
'source' => apply_filters( 'qmx/image-size/source', $source, $id, $size )
),
$size
);
}
public function name() {
return __( 'Image Sizes', 'query-monitor-extend' );
}
public function process() {
$this->_process_added_image_sizes();
$this->data['sizes'] = array_map( array( &$this, 'add_ratio' ), $this->data['sizes'] );
$counts = array( 'dimensions' => array(), 'ratios' => array() );
foreach ( $this->data['sizes'] as $size ) {
$key = $size['width'] . ':' . $size['height'] . ' - ' . $size['crop'];
array_key_exists( $key, $counts['dimensions'] )
? $counts['dimensions'][$key]++
: $counts['dimensions'][$key] = 1;
$key = $size['ratio'] . ' - ' . $size['crop'];
if ( 0 !== $size['ratio'] )
array_key_exists( $key, $counts['ratios'] )
? $counts['ratios'][$key]++
: $counts['ratios'][$key] = 1;
}
foreach ( array( 'dimensions', 'ratios' ) as $type )
$counts[$type] = array_filter( $counts[$type], function( $v ) { return $v > 1; } );
$this->data['_duplicates'] = $counts;
}
private function add_ratio( array $size ) {
if (
!array_key_exists( 'width', $size )
|| !array_key_exists( 'height', $size )
)
return $size;
$num1 = $size['width'];
$num2 = $size['height'];
while ( 0 !== $num2 ) {
$t = $num1 % $num2;
$num1 = $num2;
$num2 = $t;
}
$size['_gcd'] = $num1; // greatest common denominator
unset( $num1, $num2 );
$size['ratio'] = (
0 === $size['height']
? 0
: $size['width'] / $size['height']
);
return $size;
}
public function add_inline_script() {
wp_add_inline_script( 'query-monitor', $this->_inlineScript_queryMonitor() );
}
protected function _inlineScript_queryMonitor() {
ob_start();
?>
if ( window.jQuery ) {
jQuery( function( $ ) {
$( 'td[data-qmx-image-size-width]' )
.on( 'mouseenter', function() { qmx_image_size_highlighter__mouseenter( 'width', this ); } )
.on( 'mouseleave', function() { qmx_image_size_highlighter__mouseleave( 'width', this ); } );
$( 'td[data-qmx-image-size-height]' )
.on( 'mouseenter', function() { qmx_image_size_highlighter__mouseenter( 'height', this ); } )
.on( 'mouseleave', function() { qmx_image_size_highlighter__mouseleave( 'height', this ); } );
$( 'td[data-qmx-image-size-ratio]' )
.on( 'mouseenter', function() { qmx_image_size_highlighter__mouseenter( 'ratio', this ); } )
.on( 'mouseleave', function() { qmx_image_size_highlighter__mouseleave( 'ratio', this ); } );
} );
function qmx_image_size_highlighter__mouseenter( prop, el ) {
jQuery( el ).addClass( 'qm-highlight' );
var tr = jQuery( el ).closest( 'tr' );
var value = jQuery( el ).attr( 'data-qmx-image-size-' + prop );
var table = jQuery( el ).closest( 'table' ).find( 'tr[data-qmx-image-size-' + prop + '="' + value + '"]' ).not( tr ).addClass( 'qm-highlight' );
}
function qmx_image_size_highlighter__mouseleave( prop, el ) {
jQuery( el ).removeClass( 'qm-highlight' );
jQuery( el ).closest( 'table' ).find( 'tr.qm-highlight' ).removeClass( 'qm-highlight' );
}
}
<?php
return ob_get_clean();
}
}
QMX_Collectors::add( new QMX_Collector_Image_Sizes );
?>

View File

@@ -0,0 +1,79 @@
<?php
/**
* Paths collector.
*
* @package query-monitor-extend
*/
class QMX_Collector_Paths extends QMX_Collector {
public $id = 'paths';
public function name() {
return __( 'Paths', 'query-monitor-extend' );
}
function process() {
$this->data['paths'] = apply_filters( 'qmx/collector/paths', array(
'ABSPATH' => ABSPATH,
'COOKIEPATH' => COOKIEPATH,
'SITECOOKIEPATH' => SITECOOKIEPATH,
'DOMAIN_CURRENT_SITE' => defined( 'DOMAIN_CURRENT_SITE' ) ? DOMAIN_CURRENT_SITE : 'undefined',
'PATH_CURRENT_SITE' => defined( 'PATH_CURRENT_SITE' ) ? PATH_CURRENT_SITE : 'undefined',
'WP_SITEURL' => defined( 'WP_SITEURL' ) ? WP_SITEURL : 'undefined',
'site_url()' => site_url(),
'get_site_url()' => get_site_url(),
'network_site_url()' => network_site_url(),
'WP_HOME' => defined( 'WP_HOME' ) ? WP_HOME : 'undefined',
'home_url()' => home_url(),
'get_home_url()' => get_home_url(),
'network_home_url()' => network_home_url(),
'get_home_path()' => function_exists( 'get_home_path' ) ? get_home_path() : '',
'WP_CONTENT_URL' => WP_CONTENT_URL,
'WP_CONTENT_DIR' => WP_CONTENT_DIR,
'content_url()' => content_url(),
'WP_PLUGIN_URL' => WP_PLUGIN_URL,
'WP_PLUGIN_DIR' => WP_PLUGIN_DIR,
'PLUGINS_COOKIE_PATH' => PLUGINS_COOKIE_PATH,
'plugins_url()' => plugins_url(),
'plugin_dir_url( __FILE__ )' => plugin_dir_url( __FILE__ ),
'plugin_dir_path( __FILE__ )' => plugin_dir_path( __FILE__ ),
'plugin_basename( __FILE__ )' => plugin_basename( __FILE__ ),
'WPMU_PLUGIN_DIR' => WPMU_PLUGIN_DIR,
'WPMU_PLUGIN_URL' => WPMU_PLUGIN_URL,
'get_theme_root()' => get_theme_root(),
'get_theme_roots()' => get_theme_roots(),
'get_theme_root_uri()' => get_theme_root_uri(),
'get_template_directory()' => get_template_directory(),
'TEMPLATEPATH' => TEMPLATEPATH,
'get_template_directory_uri()' => get_template_directory_uri(),
'get_stylesheet_uri()' => get_stylesheet_uri(),
'get_stylesheet_directory()' => get_stylesheet_directory(),
'STYLESHEETPATH' => STYLESHEETPATH,
'get_stylesheet_directory_uri()' => get_stylesheet_directory_uri(),
'admin_url()' => admin_url(),
'get_admin_url()' => get_admin_url(),
'network_admin_url()' => network_admin_url(),
'ADMIN_COOKIE_PATH' => ADMIN_COOKIE_PATH,
'WPINC' => WPINC,
'includes_url()' => includes_url(),
'WP_LANG_DIR' => WP_LANG_DIR,
'BLOGUPLOADDIR' => defined( 'BLOGUPLOADDIR' ) ? BLOGUPLOADDIR : 'undefined',
'UPLOADBLOGSDIR' => defined( 'UPLOADBLOGSDIR' ) ? UPLOADBLOGSDIR : 'undefined',
'UPLOADS' => defined( 'UPLOADS' ) ? UPLOADS : 'undefined',
'wp_upload_dir()' => wp_upload_dir(),
) );
ksort( $this->data['paths'] );
}
}
function register_qmx_collector_paths( array $collectors, QueryMonitorExtend $qmx ) {
$collectors['paths'] = new QMX_Collector_Paths;
return $collectors;
}
add_filter( 'qmx/collectors', 'register_qmx_collector_paths', 10, 2 );

View File

@@ -0,0 +1,70 @@
<?php
/**
* Time collector.
*
* @package query-monitor-extend
*/
class QMX_Collector_Time extends QMX_Collector {
public $id = 'time';
public function name() {
return __( 'Time', 'query-monitor-extend' );
}
function process() {
$this->data['functions'] = array(
'UTC' => 'get_utc',
'Server' => 'get_server',
'WordPress' => 'get_wp',
'Browser' => 'get_browser',
);
}
function get_utc() {
$datetime = date_create( "now", new DateTimeZone( 'UTC' ) );
$datetime->setTimezone( new DateTimeZone( 'UTC' ) );
return $datetime->format( 'D, M j, Y H:i:s' );
}
function get_server() {
$datetime = date_create( "now", new DateTimeZone( 'UTC' ) );
if ( !empty( ini_get( 'date.timezone' ) ) )
$datetime->setTimezone( new DateTimeZone( ini_get( 'date.timezone' ) ) );
return $datetime->format( 'D, M j, Y H:i:s' );
}
function get_server_offset() {
$datetime = date_create( "now", new DateTimeZone( 'UTC' ) );
if ( !empty( ini_get( 'date.timezone' ) ) )
$datetime->setTimezone( new DateTimeZone( ini_get( 'date.timezone' ) ) );
return $datetime->format( 'Z' );
}
function get_wp() {
return current_time( 'D, M j, Y H:i:s' );
}
function get_wp_offset() {
return get_option( 'gmt_offset' );
}
function get_browser() {
return '-';
}
}
function register_qmx_collector_time( array $collectors, QueryMonitorExtend $qmx ) {
$collectors['time'] = new QMX_Collector_Time;
return $collectors;
}
add_filter( 'qmx/collectors', 'register_qmx_collector_time', 10, 2 );

View File

@@ -0,0 +1,51 @@
<?php
/**
* Var dumps collector.
*
* @package query-monitor-extend
*/
class QMX_Collector_Var_Dumps extends QMX_Collector {
public $id = 'var_dumps';
function __construct() {
add_action( 'qmx/var_dump', array( &$this, 'collect' ), 10, 2 );
parent::__construct();
$this->data['vars'] = array();
}
public function name() {
return __( 'Var Dumps', 'query-monitor-extend' );
}
public function collect( $var, $label = null ) {
if ( is_null( $label ) )
$label = time();
else if ( array_key_exists( $label, $this->data['vars'] ) )
$label .= ' (' . time() . ')';
$this->data['vars'][$label] = $var;
}
}
QMX_Collectors::add( new QMX_Collector_Var_Dumps );
// Backwards compatibility
if ( !function_exists( 'qmx_dump' ) ) {
function qmx_dump( $var, $label = null ) {
if ( QMX_Collectors::get( 'var_dumps' ) )
QMX_Collectors::get( 'var_dumps' )->collect( $var, $label );
}
}
if ( !function_exists( 'qm_dump' ) ) {
function qm_dump( $var, $label = null ) {
qmx_dump( $var, $label );
}
}

View File

@@ -0,0 +1,130 @@
<?php
/**
* Output class to adjust color of admin bar item.
*/
class QMX_Admin_Bar {
protected $class_to_color = array(
'alert' => '#f60',
'error' => '#c00',
'notice' => '#740',
'strict' => '#3c3c3c',
'warning' => '#c00',
'expensive' => '#b60',
'deprecated' => '#3c3c3c',
);
protected function __construct() {
$this->collectors = array(
'assets_scripts' => QM_Collectors::get( 'assets_scripts' ),
'assets_styles' => QM_Collectors::get( 'assets_styles' ),
'db_queries' => QM_Collectors::get( 'db_queries' ),
'http' => QM_Collectors::get( 'http' ),
'php_errors' => QM_Collectors::get( 'php_errors' ),
);
add_filter( 'qm/output/menu_class', array( $this, 'filter__qm_output_menu_class' ) );
$this->process_and_print_styles();
}
public static function get_instance() {
static $_instance = null;
if ( is_null( $_instance ) )
$_instance = new self;
return $_instance;
}
function filter__qm_output_menu_class( $classes ) {
return $classes;
}
function process_and_print_styles() {
$colors = array(
'#c00' => 0,
'#f60' => 0,
'#b60' => 0,
'#740' => 0,
'#3c3c3c' => 0,
);
// count PHP errors
$data = $this->collectors['php_errors']->get_data();
if ( !empty( $data['errors'] ) )
foreach ( $data['errors'] as $type => $errors )
$colors[$this->class_to_color[$type]] = count( $errors );
foreach ( array( 'assets_styles', 'assets_scripts' ) as $assets ) {
// count broken assets
$data = $this->collectors[$assets]->get_data();
if ( !empty( $data['broken'] ) )
$colors[$this->class_to_color['error']] += count( $data['broken'] );
// count missing assets
if ( !empty( $data['missing'] ) )
$colors[$this->class_to_color['error']] += count( $data['missing'] );
}
// count database query errors
$data = $this->collectors['db_queries']->get_errors();
if ( !empty( $data ) )
$colors[$this->class_to_color['error']] += count( $data );
// count expensive database queries
$data = $this->collectors['db_queries']->get_expensive();
if ( !empty( $data ) )
$colors[$this->class_to_color['expensive']] += count( $data );
// count HTTP alerts
$data = $this->collectors['http']->get_data();
if ( !empty( $data['errors']['alert'] ) )
$colors[$this->class_to_color['alert']] += count( $data['errors']['alert'] );
// count HTTP warnings
if ( !empty( $data['errors']['warning'] ) )
$colors[$this->class_to_color['warning']] += count( $data['errors']['warning'] );
$colors = array_filter( $colors );
$total = array_sum( $colors );
if ( QueryMonitorExtend::is_debugging() )
error_log( print_r( $colors, true ) );
$previous = 0;
$gradient = array();
foreach ( $colors as $color => $count ) {
$percentage = floor( ( $count / $total ) * 100 );
$gradient[] = $color . ' ' . $previous . '%';
$gradient[] = $color . ' ' . min( 100, $percentage + $previous ) . '%';
$previous = $percentage + $previous;
}
?>
<style type="text/css">
#wp-admin-bar-query-monitor {
background: -webkit-linear-gradient( left, <?php echo implode( ', ', $gradient ) ?> ) !important;
background: -moz-linear-gradient( left, <?php echo implode( ', ', $gradient ) ?> ) !important;
background: linear-gradient( to right, <?php echo implode( ', ', $gradient ) ?> ) !important;
}
</style>
<?php
}
}
function register_qmx_output_html_admin_bar( array $output ) {
if ( QM_Dispatchers::get( 'html' )->is_active() )
QMX_Admin_Bar::get_instance();
return $output;
}
add_filter( 'qmx/outputter/html', 'register_qmx_output_html_admin_bar', 70 );

View File

@@ -0,0 +1,12 @@
<?php
/**
* Abstract output class for HTML pages.
*
* @package query-monitor-extend
*/
abstract class QMX_Output_Html extends QM_Output_Html {
public function panel_menu( array $menu ) { return $menu; }
}

View File

@@ -0,0 +1,96 @@
<?php
/**
* Constants output for HTML pages.
*
* @package query-monitor-extend
*/
class QMX_Output_Html_Constants extends QMX_Output_Html {
public function __construct( QMX_Collector $collector ) {
parent::__construct( $collector );
add_filter( 'qm/output/panel_menus', array( &$this, 'panel_menu' ), 60 );
}
public function output() {
$data = $this->collector->get_data();
echo '<div class="qm" id="' . esc_attr( $this->collector->id() ) . '">';
if ( !empty( $data['constants'] ) ) {
echo '<table class="qm-sortable">';
echo '<caption class="qm-screen-reader-text">' . esc_html( $this->collector->name() ) . '</caption>';
echo '<thead>';
echo '<tr>';
echo '<th scope="col" class="qm-num qm-sorted-asc qm-sortable-column">';
echo $this->build_sorter( __( '', 'query-monitor-extend' ) );
echo '</th>';
echo '<th scope="col" class="qm-sortable-column">';
echo $this->build_sorter( __( 'Constant', 'query-monitor-extend' ) );
echo '</th>';
echo '<th scope="col" class="qm-ltr">';
echo __( 'Value', 'query-monitor-extend' );
echo '</th>';
echo '<th scope="col" class="qm-sortable-column">';
echo $this->build_sorter( __( 'Type', 'query-monitor-extend' ) );
echo '</th>';
echo '</tr>';
echo '</thead>';
echo '<tbody>';
$i = 1;
$bools = array( true => 'true', false => 'false' );
foreach ( $data['constants'] as $constant => $value ) {
echo '<tr>';
echo '<td class="qm-num">' . $i++ . '</td>';
echo '<td class="qm-ltr" data-qm-sort-weight="' . strtolower( esc_attr( $constant ) ) . '"><code style="user-select: all;">' . esc_html( $constant ) . '</code></td>';
echo '<td ' . ( is_bool( $value ) ? ' class="qm-' . $bools[$value] . '"' : '' ) . '>' . ( is_bool( $value ) ? strtoupper( $bools[$value] ) : esc_html( $value ) ) . '</td>';
echo '<td class="qm-ltr">' . esc_html( gettype( $value ) ) . '</td>';
echo '</tr>';
}
echo '</tbody>';
echo '<tfoot>';
echo '</tfoot>';
echo '</table>';
} else {
echo '<div class="qm-none">';
echo '<p>' . esc_html__( 'None', 'query-monitor' ) . '</p>';
echo '</div>';
}
echo '</div>';
}
public function panel_menu( array $menu ) {
$menu['constants'] = $this->menu( array(
'title' => esc_html__( 'Constants', 'query-monitor-extend' ),
'id' => 'query-monitor-extend-constants',
) );
return $menu;
}
}
function register_qmx_output_html_constants( array $output ) {
if ( $collector = QMX_Collectors::get( 'constants' ) ) {
$output['constants'] = new QMX_Output_Html_Constants( $collector );
}
return $output;
}
add_filter( 'qmx/outputter/html', 'register_qmx_output_html_constants', 70 );

View File

@@ -0,0 +1,173 @@
<?php
/**
* Files output for HTML pages.
*
* @package query-monitor-extend
*/
class QMX_Output_Html_Files extends QMX_Output_Html {
public function __construct( QMX_Collector $collector ) {
parent::__construct( $collector );
add_filter( 'qm/output/title', array( &$this, 'admin_title' ), 40 );
add_filter( 'qm/output/panel_menus', array( &$this, 'panel_menu' ), 60 );
}
public function output() {
$data = $this->collector->get_data();
echo '<div class="qm" id="' . esc_attr( $this->collector->id() ) . '">';
if ( !empty( $data['files'] ) ) {
$files_with_errors = 0;
$path_components = $components = array();
$largest_file = array(
'path' => null,
'size' => 0
);
foreach ( $data['files'] as &$file ) {
$file['_path_components'] = array();
foreach ( array_filter( explode( '/', str_replace( ABSPATH, '', dirname( $file['path'] ) ) ) ) as $path_component ) {
$path_components[$path_component]
= $file['_path_components'][$path_component]
= 1;
foreach ( explode( '-', $path_component ) as $smaller_path_component )
$path_components[$smaller_path_component]
= $file['_path_components'][$smaller_path_component]
= 1;
}
$components[$file['component']->name] = 1;
}
echo '<table class="qm-sortable">';
echo '<caption class="qm-screen-reader-text">' . esc_html( $this->collector->name() ) . '</caption>';
echo '<thead>';
echo '<tr>';
echo '<th scope="col" class="qm-num qm-sorted-asc qm-sortable-column">';
echo $this->build_sorter( __( '', 'query-monitor-extend' ) );
echo '</th>';
echo '<th scope="col" class="qm-filterable-column">';
echo $this->build_filter( 'path', array_map( 'esc_attr', array_keys( $path_components ) ), __( 'Path', 'query-monitor-extend' ) );
echo '</th>';
echo '<th scope="col" class="qm-ltr qm-sortable-column">';
echo $this->build_sorter( __( 'Filesize', 'query-monitor-extend' ) );
echo '</th>';
echo '<th scope="col" class="qm-filterable-column">';
echo $this->build_filter( 'component', array_map( 'esc_attr', array_keys( $components ) ), __( 'Component', 'query-monitor-extend' ) );
echo '</th>';
echo '</tr>';
echo '</thead>';
echo '<tbody>';
foreach ( $data['files'] as $i => $file ) {
if ( filesize( $file['path'] ) > $largest_file['size'] )
$largest_file = array(
'path' => $file['path'],
'size' => filesize( $file['path'] ),
);
if ( !empty( $file['has_error'] ) )
$files_with_errors++;
echo '<tr ' .
'data-qm-component="' . esc_attr( $file['component']->name ) . '"' .
'data-qm-path="' . esc_attr( implode( ' ', array_keys( $file['_path_components'] ) ) ) . '"' .
( !empty( $file['has_error'] ) ? ' class="qm-warn"' : '' ) .
'>';
echo '<td class="qm-num">' . ( $i + 1 ) . '</td>';
echo '<td title="' . esc_attr( $file['path'] ) . '">' . esc_html( str_replace( ABSPATH, '/', $file['path'] ) ) . '</td>';
echo '<td data-qm-sort-weight="' . filesize( $file['path'] ) . '">' . $this->human_file_size( filesize( $file['path'] ) ) . '</td>';
echo '<td>' . esc_html( $file['component']->name ) . '</td>';
echo '</tr>';
}
echo '</tbody>';
echo '<tfoot>';
echo '<tr class="qm-items-shown qm-hide">';
echo '<td colspan="4">';
printf(
esc_html__( 'Files in filter: %s', 'query-monitor-extend' ),
'<span class="qm-items-number">' . esc_html( number_format_i18n( count( $data['files']) ) ) . '</span>'
);
echo '</td>';
echo '</tr>';
echo '<tr>';
echo '<td colspan="2">' .
'Total: <span class="qm-items-number">' . esc_html( number_format_i18n( count( $data['files'] ) ) ) . '</span>' .
(
!empty( $files_with_errors )
? ', With error(s): <span>' . esc_html( number_format_i18n( $files_with_errors ) ) . '</span>'
: ''
) .
'</td>';
echo '<td>Largest: <abbr title="' . esc_attr( $largest_file['path'] ) . '">' . $this->human_file_size( $largest_file['size'] ) . '</td>';
echo '<td>Components: ' . count( $components ) . '</td>';
echo '</tr>';
echo '</tfoot>';
echo '</table>';
echo '<style type="text/css">.qm-hide-path { display: none; }</style>';
} else {
echo '<div class="qm-none">';
echo '<p>' . esc_html__( 'None', 'query-monitor' ) . '</p>';
echo '</div>';
}
echo '</div>';
}
public function admin_title( array $title ) {
$data = $this->collector->get_data();
if ( !empty( $data['files'] ) ) {
$_title = sprintf( esc_html_x( '%s F', 'Files count', 'query-monitor-extend' ), number_format_i18n( count( $data['files'] ) ) );
$_title = preg_replace( '#\s?([^0-9,\.]+)#', '<small>$1</small>', $_title );
$title[] = $_title;
}
return $title;
}
public function panel_menu( array $menu ) {
$menu['files'] = $this->menu( array(
'title' => esc_html__( 'Files', 'query-monitor-extend' ),
'id' => 'query-monitor-extend-files',
) );
return $menu;
}
private function human_file_size( $bytes ) {
$filesize_units = 'BKMGTP';
$factor = floor( ( strlen( $bytes ) - 1 ) / 3 );
return sprintf( "%.2f", $bytes / pow( 1024, $factor ) ) . @$filesize_units[$factor];
}
}
function register_qmx_output_html_files( array $output ) {
if ( $collector = QMX_Collectors::get( 'files' ) ) {
$output['files'] = new QMX_Output_Html_Files( $collector );
}
return $output;
}
add_filter( 'qmx/outputter/html', 'register_qmx_output_html_files', 70 );

View File

@@ -0,0 +1,83 @@
<?php
/**
* Heartbeat output for HTML pages.
*
* @package query-monitor-extend
*/
class QMX_Output_Html_Heartbeat extends QMX_Output_Html {
public function __construct( QMX_Collector $collector ) {
parent::__construct( $collector );
add_filter( 'qm/output/panel_menus', array( &$this, 'panel_menu' ), 60 );
}
public function output() {
$data = $this->collector->get_data();
echo '<div class="qm" id="' . esc_attr( $this->collector->id() ) . '">';
if ( $this->collector->qm_no_jquery() ) {
echo '<div class="qm-none">';
echo '<p>Heartbeat logging requires jQuery, which has been prevented by <code>QM_NO_JQUERY</code>.</p>';
echo '</div>';
} else if ( wp_script_is( 'heartbeat', 'done' ) ) {
echo '<table class="qm-sortable">';
echo '<caption class="qm-screen-reader-text">' . esc_html( $this->collector->name() ) . '</caption>';
echo '<thead>';
echo '<tr>';
echo '<th scope="col" class="qm-num qm-sorted-asc qm-sortable-column"></th>';
echo '<th scope="col">Lub</th>';
echo '<th scope="col">Dub</th>';
echo '<th scope="col">Time since last</th>';
echo '<th scope="col">Duration</th>';
echo '</tr>';
echo '</thead>';
echo '<tbody>';
echo '<tr class="listening">';
echo '<td colspan="5">';
echo '<div class="qm-none"><p>Listening for first heartbeat...</p></div>';
echo '</td>';
echo '</tr>';
echo '</tbody>';
echo '</table>';
echo '<script type="text/javascript">qmx_heartbeat.populate_table();</script>';
} else {
echo '<div class="qm-none">';
echo '<p>' . esc_html__( 'No heartbeat detected.', 'query-monitor' ) . '</p>';
echo '</div>';
}
echo '</div>';
}
public function panel_menu( array $menu ) {
$data = $this->collector->get_data();
$menu['heartbeat'] = $this->menu( array(
'title' => esc_html__( 'Heartbeats (0)' ),
'id' => 'query-monitor-extend-heartbeat',
) );
return $menu;
}
}
function register_qmx_output_html_heartbeat( array $output ) {
if ( $collector = QMX_Collectors::get( 'heartbeat' ) ) {
$output['heartbeat'] = new QMX_Output_Html_Heartbeat( $collector );
}
return $output;
}
add_filter( 'qmx/outputter/html', 'register_qmx_output_html_heartbeat', 70 );

View File

@@ -0,0 +1,134 @@
<?php
/**
* Image sizes output for HTML pages.
*
* @package query-monitor-extend
*/
class QMX_Output_Html_Image_Sizes extends QMX_Output_Html {
public function __construct( QMX_Collector $collector ) {
parent::__construct( $collector );
add_filter( 'qm/output/panel_menus', array( &$this, 'panel_menu' ), 60 );
}
public function output() {
$data = $this->collector->get_data();
echo '<div class="qm" id="' . esc_attr( $this->collector->id() ) . '">';
if ( !empty( $data['sizes'] ) ) {
echo '<table class="qm-sortable">';
echo '<caption class="qm-screen-reader-text">' . esc_html( $this->collector->name() ) . '</caption>';
echo '<thead>';
echo '<tr>';
echo '<th scope="col" class="qm-num qm-sorted-asc qm-sortable-column">';
echo $this->build_sorter( __( '', 'query-monitor-extend' ) );
echo '</th>';
echo '<th scope="col" class="qm-sortable-column">';
echo $this->build_sorter( __( 'ID', 'query-monitor-extend' ) );
echo '</th>';
echo '<th scope="col" class="qm-num qm-sortable-column">';
echo $this->build_sorter( __( 'Width', 'query-monitor-extend' ) );
echo '</th>';
echo '<th scope="col" class="qm-num qm-sortable-column">';
echo $this->build_sorter( __( 'Height', 'query-monitor-extend' ) );
echo '</th>';
echo '<th scope="col" class="qm-num qm-sortable-column">';
echo $this->build_sorter( __( 'Ratio', 'query-monitor-extend' ) );
echo '</th>';
echo '<th scope="col" class="qm-num">';
echo __( 'Cropped', 'query-monitor-extend' );
echo '</th>';
echo '<th scope="col" class="qm-sortable-column">';
echo $this->build_sorter( __( 'Source', 'query-monitor-extend' ) );
echo '</th>';
echo '</tr>';
echo '</thead>';
echo '<tbody>';
$sources = array();
foreach ( $data['sizes'] as $id => $row ) {
$ratio = array( $row['width'], $row['height'] );
if (
!empty( $row['width'] )
&& !empty( $row['height'] )
)
$ratio = array( $row['width'] / $row['_gcd'], $row['height'] / $row['_gcd'] );
if ( $ratio === array( $row['width'], $row['height'] ) )
$ratio = array( '&mdash;' );
echo '<tr data-qmx-image-size-width="' . esc_attr( $row['width'] ) . '" data-qmx-image-size-height="' . esc_attr( $row['height'] ) . '" data-qmx-image-size-ratio="' . esc_attr( $row['ratio'] ) . '">';
echo '<td class="qm-num">' . esc_html( $row['num'] ) . '</td>';
echo '<td class="qm-ltr">' . esc_html( $id ) . '</td>';
echo '<td class="qm-num" data-qmx-image-size-width="' . esc_attr( $row['width'] ) . '">' . esc_html( $row['width'] ) . '</td>';
echo '<td class="qm-num" data-qmx-image-size-height="' . esc_attr( $row['height'] ) . '">' . esc_html( $row['height'] ) . '</td>';
echo '<td class="qm-num" data-qmx-image-size-ratio="' . esc_attr( $row['ratio'] ) . '" data-qm-sort-weight="' . esc_attr( $row['ratio'] ) . '">' . esc_html( implode( ':', $ratio ) ) . '</td>';
echo '<td class="qm-num qm-true">' . ( $row['crop'] ? '<span class="dashicons dashicons-yes"></span>' : '' ) . '</td>';
echo '<td class="qm-ltr">' . esc_html( $row['source'] ) . '</td>';
echo '</tr>';
array_key_exists( $row['source'], $sources ) ? $sources[$row['source']]++ : $sources[$row['source']] = 1;
}
echo '</tbody>';
echo '<tfoot>';
if ( !empty( $sources ) )
$sources = array_map( function( $k, $v ) { return ucwords( $k ) . ': ' . $v; }, array_keys( $sources ), $sources );
echo '<tr>';
echo '<td class="qm-num">Total: <span class="qm-items-number">' . esc_html( number_format_i18n( count( $data['sizes'] ) ) ) . '</span></td>';
echo '<td>&nbsp;</td>';
echo '<td colspan="2">Duplicates: <span class="qm-items-number">' . esc_html( number_format_i18n( array_sum( $data['_duplicates']['dimensions'] ) ) ) . '</span></td>';
echo '<td colspan="2">Duplicates: <span class="qm-items-number">' . esc_html( number_format_i18n( array_sum( $data['_duplicates']['ratios'] ) ) ) . '</span></td>';
echo '<td>' . implode( ', ', $sources ) . '</td>';
echo '</tr>';
echo '</tfoot>';
echo '</table>';
} else {
echo '<div class="qm-none">';
echo '<p>' . esc_html__( 'None', 'query-monitor' ) . '</p>';
echo '</div>';
}
echo '</div>';
}
public function panel_menu( array $menu ) {
$menu['image_sizes'] = $this->menu( array(
'title' => esc_html__( 'Image Sizes', 'query-monitor-extend' ),
'id' => 'query-monitor-extend-image_sizes',
) );
return $menu;
}
}
function register_qmx_output_html_image_sizes( array $output ) {
if ( $collector = QMX_Collectors::get( 'image_sizes' ) ) {
$output['image_sizes'] = new QMX_Output_Html_Image_Sizes( $collector );
}
return $output;
}
add_filter( 'qmx/outputter/html', 'register_qmx_output_html_image_sizes', 70 );

View File

@@ -0,0 +1,94 @@
<?php
/**
* Paths output for HTML pages.
*
* @package query-monitor-extend
*/
class QMX_Output_Html_Paths extends QMX_Output_Html {
public function __construct( QMX_Collector $collector ) {
parent::__construct( $collector );
add_filter( 'qm/output/panel_menus', array( &$this, 'panel_menu' ), 60 );
}
public function output() {
$data = $this->collector->get_data();
echo '<div class="qm" id="' . esc_attr( $this->collector->id() ) . '">';
if ( !empty( $data['paths'] ) ) {
echo '<table class="qm-sortable">';
echo '<caption class="qm-screen-reader-text">' . esc_html( $this->collector->name() ) . '</caption>';
echo '<thead>';
echo '<tr>';
echo '<th scope="col" class="qm-sorted-asc qm-sortable-column">';
echo $this->build_sorter( __( 'Constant/Function', 'query-monitor-extend' ) );
echo '</th>';
echo '<th scope="col" class="qm-ltr">';
echo __( 'Path', 'query-monitor-extend' );
echo '</th>';
echo '</tr>';
echo '</thead>';
echo '<tbody>';
foreach ( $data['paths'] as $var => $value ) {
echo '<tr>';
echo '<td class="qm-ltr"><code style="user-select: all;">' . esc_html( $var ) . '</code></td>';
if ( is_string( $value ) ) {
echo '<td>' . esc_html( $value ) . '</td>';
} else {
echo '<td class="qm-has-inner qm-ltr">';
self::output_inner( $value );
echo '</td>';
}
echo '</tr>';
}
echo '</tbody>';
echo '<tfoot>';
echo '</tfoot>';
echo '</table>';
} else {
echo '<div class="qm-none">';
echo '<p>' . esc_html__( 'None', 'query-monitor' ) . '</p>';
echo '</div>';
}
echo '</div>';
}
public function panel_menu( array $menu ) {
$menu['paths'] = $this->menu( array(
'title' => esc_html__( 'Paths', 'query-monitor-extend' ),
'id' => 'query-monitor-extend-paths',
) );
return $menu;
}
}
function register_qmx_output_html_paths( array $output ) {
if ( $collector = QMX_Collectors::get( 'paths' ) ) {
$output['paths'] = new QMX_Output_Html_Paths( $collector );
}
return $output;
}
add_filter( 'qmx/outputter/html', 'register_qmx_output_html_paths', 70 );

View File

@@ -0,0 +1,132 @@
<?php
/**
* Paths output for HTML pages.
*
* @package query-monitor-extend
*/
class QMX_Output_Html_Time extends QMX_Output_Html {
public function __construct( QMX_Collector $collector ) {
parent::__construct( $collector );
add_filter( 'qm/output/panel_menus', array( &$this, 'panel_menu' ), 60 );
}
public function output() {
$data = $this->collector->get_data();
$wp_offset = get_option( 'gmt_offset' );
echo '<div class="qm qm-non-tabular" id="' . esc_attr( $this->collector->id() ) . '">' .
'<div class="qm-boxed">';
foreach ( $data['functions'] as $label => $function ) {
if ( is_callable( array( $this->collector, $function ) ) )
echo '<div class="qm-section">' .
'<h2>' . esc_html( $label ) . '</h2>' .
'<p><code id="qm-time-' . sanitize_title( $label ) . '">' . $this->collector->$function() . '</code></p>' .
'</div>';
}
echo '</div>';
?>
<script type="text/javascript">
( function() {
if ( 'function' !== typeof IntersectionObserver )
return;
var qmx_time_interval = 0;
var observer = new IntersectionObserver( function( entries, observer ) {
if ( !entries[0].isIntersecting ) {
clearInterval( qmx_time_interval );
return;
}
var qmx_time_months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
var qmx_time_days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
var qmx_time_container = document.getElementById( 'qm-time' );
var qmx_time_utc = document.getElementById( 'qm-time-utc' );
var qmx_time_server = document.getElementById( 'qm-time-server' );
var qmx_time_wp = document.getElementById( 'qm-time-wordpress' );
var qmx_time_browser = document.getElementById( 'qm-time-browser' );
if ( qmx_time_container ) {
qmx_time_interval = setInterval( function() {
var d = new Date();
var UTC_string = d.toUTCString();
var utc_time = d.getTime() + ( d.getTimezoneOffset() * 60 * 1000 );
var server = new Date( utc_time + ( <?php echo esc_js( $this->collector->get_server_offset() ) ?> * 1000 ) );
var wp = new Date( utc_time + ( <?php echo esc_js( $this->collector->get_wp_offset() * HOUR_IN_SECONDS ) ?> * 1000 ) );
qmx_time_utc.innerHTML =
qmx_time_days[d.getUTCDay()] + ', '
+ qmx_time_months[d.getUTCMonth()] + ' '
+ d.getUTCDate() + ', '
+ d.getUTCFullYear() + ' '
+ ( 10 > d.getUTCHours() ? '0' : '' ) + d.getUTCHours()
+ ':' + ( 10 > d.getUTCMinutes() ? '0' : '' ) + d.getUTCMinutes()
+ ':' + ( 10 > d.getUTCSeconds() ? '0' : '' ) + d.getUTCSeconds();
qmx_time_server.innerHTML =
qmx_time_days[server.getDay()] + ', '
+ qmx_time_months[server.getMonth()] + ' '
+ server.getDate() + ', '
+ server.getFullYear() + ' '
+ ( 10 > server.getHours() ? '0' : '' ) + server.getHours()
+ ':' + ( 10 > server.getMinutes() ? '0' : '' ) + server.getMinutes()
+ ':' + ( 10 > server.getSeconds() ? '0' : '' ) + server.getSeconds();
qmx_time_wp.innerHTML =
qmx_time_days[wp.getDay()] + ', '
+ qmx_time_months[wp.getMonth()] + ' '
+ wp.getDate() + ', '
+ wp.getFullYear() + ' '
+ ( 10 > wp.getHours() ? '0' : '' ) + wp.getHours()
+ ':' + ( 10 > wp.getMinutes() ? '0' : '' ) + wp.getMinutes()
+ ':' + ( 10 > wp.getSeconds() ? '0' : '' ) + wp.getSeconds();
qmx_time_browser.innerHTML =
qmx_time_days[d.getDay()] + ', '
+ qmx_time_months[d.getMonth()] + ' '
+ d.getDate() + ', '
+ d.getFullYear() + ' '
+ ( 10 > d.getHours() ? '0' : '' ) + d.getHours()
+ ':' + ( 10 > d.getMinutes() ? '0' : '' ) + d.getMinutes()
+ ':' + ( 10 > d.getSeconds() ? '0' : '' ) + d.getSeconds();
}, 1000 );
}
} );
observer.observe( document.getElementById( 'qm-time' ) );
} () );
</script>
<?php
echo '</div>';
}
public function panel_menu( array $menu ) {
$menu['time'] = $this->menu( array(
'title' => esc_html__( 'Time', 'query-monitor-extend' ),
'id' => 'query-monitor-extend-time',
) );
return $menu;
}
}
function register_qmx_output_html_time( array $output ) {
if ( $collector = QMX_Collectors::get( 'time' ) ) {
$output['time'] = new QMX_Output_Html_Time( $collector );
}
return $output;
}
add_filter( 'qmx/outputter/html', 'register_qmx_output_html_time', 70 );

View File

@@ -0,0 +1,92 @@
<?php
/**
* Var dumps output for HTML pages.
*
* @package query-monitor-extend
*/
class QMX_Output_Html_Var_Dumps extends QMX_Output_Html {
public function __construct( QMX_Collector $collector ) {
parent::__construct( $collector );
add_filter( 'qm/output/panel_menus', array( &$this, 'panel_menu' ), 60 );
}
public function output() {
$data = $this->collector->get_data();
echo '<div class="qm" id="' . esc_attr( $this->collector->id() ) . '">';
if ( !empty( $data['vars'] ) ) {
echo '<table class="qm-sortable">';
echo '<caption class="qm-screen-reader-text">' . esc_html( $this->collector->name() ) . '</caption>';
echo '<thead>';
echo '<tr>';
echo '<th scope="col" class="qm-num qm-sorted-asc qm-sortable-column">';
echo $this->build_sorter( __( '', 'query-monitor-extend' ) );
echo '</th>';
echo '<th scope="col" class="qm-sortable-column">';
echo $this->build_sorter( __( 'ID', 'query-monitor-extend' ) );
echo '</th>';
echo '<th scope="col">';
echo 'Value';
echo '</th>';
echo '</tr>';
echo '</thead>';
echo '<tbody>';
$i = 1;
foreach ( $data['vars'] as $label => $value ) {
echo '<tr>';
echo '<td class="qm-num">' . $i++ . '</td>';
echo '<td class="qm-ltr">' . esc_html( $label ) . '</td>';
echo '<td>';
echo '<textarea style="font-family: Consolas, Monaco, monospace; width: 100%; height: 200px; background-color: rgba( 255, 255, 255, 0.25 ); font-size: inherit;" readonly="readonly">';
print_r( $value );
echo '</textarea>';
echo '</td>';
echo '</tr>';
}
echo '</tbody>';
echo '</table>';
} else {
echo '<div class="qm-none">';
echo '<p>' . esc_html__( 'None', 'query-monitor' ) . '</p>';
echo '</div>';
}
echo '</div>';
}
public function panel_menu( array $menu ) {
$data = $this->collector->get_data();
$menu['var_dumps'] = $this->menu( array(
'title' => esc_html__( 'Var Dumps' . ( !empty( $data['vars'] ) ? ' (' . count( $data['vars'] ) . ')' : '' ), 'query-monitor-extend' ),
'id' => 'query-monitor-extend-var-dumps',
) );
return $menu;
}
}
function register_qmx_output_html_var_dumps( array $output ) {
if ( $collector = QMX_Collectors::get( 'var_dumps' ) ) {
$output['var_dumps'] = new QMX_Output_Html_Var_Dumps( $collector );
}
return $output;
}
add_filter( 'qmx/outputter/html', 'register_qmx_output_html_var_dumps', 70 );

View File

@@ -0,0 +1,44 @@
<?php
/**
* Query Monitor Extend plugin for WordPress
*
* @package query-monitor-extend
* @link https://github.com/crstauf/query-monitor-extend
* @author Caleb Stauffer <develop@calebstauffer.com>
*
* Plugin Name: Query Monitor Extend
* Plugin URI: https://github.com/crstauf/query-monitor-extend
* Description: Enhancements and extensions for the awesome Query Monitor plugin by John Blackbourn
* Version: 1.0
* Author: Caleb Stauffer
* Author URI: http://develop.calebstauffer.com
* QM tested up to: 3.3.1
*/
if ( !defined( 'ABSPATH' ) || !function_exists( 'add_filter' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
$qmx_dir = dirname( __FILE__ );
require_once "{$qmx_dir}/classes/Plugin.php";
if (
'cli' === php_sapi_name()
|| ( defined( 'DOING_CRON' ) && DOING_CRON )
|| ( defined( 'QM_DISABLED' ) && QM_DISABLED )
|| ( defined( 'QMX_DISABLED' ) && QMX_DISABLED )
|| !class_exists( 'QueryMonitor' )
)
return;
foreach ( array( 'QueryMonitorExtend', 'Collectors', 'Collector', 'Output' ) as $qmx_class ) {
require_once "{$qmx_dir}/classes/{$qmx_class}.php";
}
include_once "{$qmx_dir}/output/AdminBar.php";
QueryMonitorExtend::init( __FILE__ );
?>