first
This commit is contained in:
32
wp-content/plugins/query-monitor/output/Headers.php
Normal file
32
wp-content/plugins/query-monitor/output/Headers.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Abstract output class for HTTP headers.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
abstract class QM_Output_Headers extends QM_Output {
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
|
||||
$id = $this->collector->id;
|
||||
|
||||
foreach ( $this->get_output() as $key => $value ) {
|
||||
if ( ! is_scalar( $value ) ) {
|
||||
$value = json_encode( $value );
|
||||
}
|
||||
|
||||
# Remove illegal characters (Header may not contain NUL bytes)
|
||||
if ( is_string( $value ) ) {
|
||||
$value = str_replace( chr( 0 ), '', $value );
|
||||
}
|
||||
|
||||
header( sprintf( 'X-QM-%s-%s: %s', $id, $key, $value ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
626
wp-content/plugins/query-monitor/output/Html.php
Normal file
626
wp-content/plugins/query-monitor/output/Html.php
Normal file
@ -0,0 +1,626 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Abstract output class for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
abstract class QM_Output_Html extends QM_Output {
|
||||
|
||||
/**
|
||||
* @var string|false|null
|
||||
*/
|
||||
protected static $file_link_format = null;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $current_id = null;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $current_name = null;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return $this->collector->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function admin_menu( array $menu ) {
|
||||
|
||||
$menu[ $this->collector->id() ] = $this->menu( array(
|
||||
'title' => esc_html( $this->name() ),
|
||||
) );
|
||||
return $menu;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_output() {
|
||||
ob_start();
|
||||
// compat until I convert all the existing outputters to use `get_output()`
|
||||
$this->output();
|
||||
$out = (string) ob_get_clean();
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
protected function before_tabular_output( $id = null, $name = null ) {
|
||||
if ( null === $id ) {
|
||||
$id = $this->collector->id();
|
||||
}
|
||||
if ( null === $name ) {
|
||||
$name = $this->name();
|
||||
}
|
||||
|
||||
$this->current_id = $id;
|
||||
$this->current_name = $name;
|
||||
|
||||
printf(
|
||||
'<div class="qm" id="%1$s" role="tabpanel" aria-labelledby="%1$s-caption" tabindex="-1">',
|
||||
esc_attr( $id )
|
||||
);
|
||||
|
||||
echo '<table class="qm-sortable">';
|
||||
|
||||
printf(
|
||||
'<caption class="qm-screen-reader-text"><h2 id="%1$s-caption">%2$s</h2></caption>',
|
||||
esc_attr( $id ),
|
||||
esc_html( $name )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function after_tabular_output() {
|
||||
echo '</table>';
|
||||
echo '</div>';
|
||||
|
||||
$this->output_concerns();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
protected function before_non_tabular_output( $id = null, $name = null ) {
|
||||
if ( null === $id ) {
|
||||
$id = $this->collector->id();
|
||||
}
|
||||
if ( null === $name ) {
|
||||
$name = $this->name();
|
||||
}
|
||||
|
||||
$this->current_id = $id;
|
||||
$this->current_name = $name;
|
||||
|
||||
printf(
|
||||
'<div class="qm qm-non-tabular" id="%1$s" role="tabpanel" aria-labelledby="%1$s-caption" tabindex="-1">',
|
||||
esc_attr( $id )
|
||||
);
|
||||
|
||||
echo '<div class="qm-boxed">';
|
||||
|
||||
printf(
|
||||
'<h2 class="qm-screen-reader-text" id="%1$s-caption">%2$s</h2>',
|
||||
esc_attr( $id ),
|
||||
esc_html( $name )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function after_non_tabular_output() {
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
|
||||
$this->output_concerns();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function output_concerns() {
|
||||
$concerns = array(
|
||||
'concerned_actions' => array(
|
||||
__( 'Related Hooks with Actions Attached', 'query-monitor' ),
|
||||
__( 'Action', 'query-monitor' ),
|
||||
),
|
||||
'concerned_filters' => array(
|
||||
__( 'Related Hooks with Filters Attached', 'query-monitor' ),
|
||||
__( 'Filter', 'query-monitor' ),
|
||||
),
|
||||
);
|
||||
|
||||
if ( empty( $this->collector->concerned_actions ) && empty( $this->collector->concerned_filters ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
printf(
|
||||
'<div class="qm qm-concerns" id="%1$s" role="tabpanel" aria-labelledby="%1$s-caption" tabindex="-1">',
|
||||
esc_attr( $this->current_id . '-concerned_hooks' )
|
||||
);
|
||||
|
||||
echo '<table>';
|
||||
|
||||
printf(
|
||||
'<caption><h2 id="%1$s-caption">%2$s</h2></caption>',
|
||||
esc_attr( $this->current_id . '-concerned_hooks' ),
|
||||
sprintf(
|
||||
/* translators: %s: Panel name */
|
||||
esc_html__( '%s: Related Hooks with Filters or Actions Attached', 'query-monitor' ),
|
||||
esc_html( $this->name() )
|
||||
)
|
||||
);
|
||||
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col">' . esc_html__( 'Hook', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Type', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Priority', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Callback', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Component', 'query-monitor' ) . '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
|
||||
echo '<tbody>';
|
||||
|
||||
foreach ( $concerns as $key => $labels ) {
|
||||
if ( empty( $this->collector->$key ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QM_Output_Html_Hooks::output_hook_table( $this->collector->$key, true );
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
echo '</table>';
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
protected function before_debug_bar_output( $id = null, $name = null ) {
|
||||
if ( null === $id ) {
|
||||
$id = $this->collector->id();
|
||||
}
|
||||
if ( null === $name ) {
|
||||
$name = $this->name();
|
||||
}
|
||||
|
||||
printf(
|
||||
'<div class="qm qm-debug-bar" id="%1$s" role="tabpanel" aria-labelledby="%1$s-caption" tabindex="-1">',
|
||||
esc_attr( $id )
|
||||
);
|
||||
|
||||
printf(
|
||||
'<h2 class="qm-screen-reader-text" id="%1$s-caption">%2$s</h2>',
|
||||
esc_attr( $id ),
|
||||
esc_html( $name )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function after_debug_bar_output() {
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $notice
|
||||
* @return string
|
||||
*/
|
||||
protected function build_notice( $notice ) {
|
||||
$return = '<section>';
|
||||
$return .= '<div class="qm-notice">';
|
||||
$return .= '<p>';
|
||||
$return .= $notice;
|
||||
$return .= '</p>';
|
||||
$return .= '</div>';
|
||||
$return .= '</section>';
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $vars
|
||||
* @return void
|
||||
*/
|
||||
public static function output_inner( array $vars ) {
|
||||
|
||||
echo '<table>';
|
||||
|
||||
foreach ( $vars as $key => $value ) {
|
||||
echo '<tr>';
|
||||
echo '<td>' . esc_html( $key ) . '</td>';
|
||||
if ( is_array( $value ) ) {
|
||||
echo '<td>';
|
||||
self::output_inner( $value );
|
||||
echo '</td>';
|
||||
} elseif ( is_object( $value ) ) {
|
||||
echo '<td>';
|
||||
self::output_inner( get_object_vars( $value ) );
|
||||
echo '</td>';
|
||||
} elseif ( is_bool( $value ) ) {
|
||||
if ( $value ) {
|
||||
echo '<td class="qm-true">true</td>';
|
||||
} else {
|
||||
echo '<td class="qm-false">false</td>';
|
||||
}
|
||||
} else {
|
||||
echo '<td>';
|
||||
echo nl2br( esc_html( $value ) );
|
||||
echo '</td>';
|
||||
}
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
echo '</table>';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the table filter controls. Safe for output.
|
||||
*
|
||||
* @param string $name The name for the `data-` attributes that get filtered by this control.
|
||||
* @param (string|int)[] $values Option values for this control.
|
||||
* @param string $label Label text for the filter control.
|
||||
* @param array $args {
|
||||
* @type string $highlight The name for the `data-` attributes that get highlighted by this control.
|
||||
* @type string[] $prepend Associative array of options to prepend to the list of values.
|
||||
* @type string[] $append Associative array of options to append to the list of values.
|
||||
* }
|
||||
* @phpstan-param array{
|
||||
* highlight?: string,
|
||||
* prepend?: array<string, string>,
|
||||
* append?: array<string, string>,
|
||||
* } $args
|
||||
* @return string Markup for the table filter controls.
|
||||
*/
|
||||
protected function build_filter( $name, $values, $label, $args = array() ) {
|
||||
|
||||
if ( empty( $values ) || ! is_array( $values ) ) {
|
||||
return esc_html( $label ); // Return label text, without being marked up as a label element.
|
||||
}
|
||||
|
||||
if ( ! is_array( $args ) ) {
|
||||
$args = array(
|
||||
'highlight' => $args,
|
||||
);
|
||||
}
|
||||
|
||||
$args = array_merge( array(
|
||||
'highlight' => '',
|
||||
'prepend' => array(),
|
||||
'append' => array(),
|
||||
'all' => _x( 'All', '"All" option for filters', 'query-monitor' ),
|
||||
), $args );
|
||||
|
||||
$core_val = __( 'WordPress Core', 'query-monitor' );
|
||||
$core_key = array_search( $core_val, $values, true );
|
||||
|
||||
if ( 'component' === $name && count( $values ) > 1 && false !== $core_key ) {
|
||||
$args['append'][ $core_val ] = $core_val;
|
||||
$args['append']['non-core'] = __( 'Non-WordPress Core', 'query-monitor' );
|
||||
unset( $values[ $core_key ] );
|
||||
}
|
||||
|
||||
$filter_id = 'qm-filter-' . $this->collector->id . '-' . $name;
|
||||
|
||||
$out = '<div class="qm-filter-container">';
|
||||
$out .= '<label for="' . esc_attr( $filter_id ) . '">' . esc_html( $label ) . '</label>';
|
||||
$out .= '<select id="' . esc_attr( $filter_id ) . '" class="qm-filter" data-filter="' . esc_attr( $name ) . '" data-highlight="' . esc_attr( $args['highlight'] ) . '">';
|
||||
$out .= '<option value="">' . esc_html( $args['all'] ) . '</option>';
|
||||
|
||||
if ( ! empty( $args['prepend'] ) ) {
|
||||
foreach ( $args['prepend'] as $value => $label ) {
|
||||
$out .= '<option value="' . esc_attr( $value ) . '">' . esc_html( $label ) . '</option>';
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $values as $key => $value ) {
|
||||
if ( is_int( $key ) && $key >= 0 ) {
|
||||
$out .= '<option value="' . esc_attr( $value ) . '">' . esc_html( $value ) . '</option>';
|
||||
} else {
|
||||
$out .= '<option value="' . esc_attr( $key ) . '">' . esc_html( $value ) . '</option>';
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $args['append'] ) ) {
|
||||
foreach ( $args['append'] as $value => $label ) {
|
||||
$out .= '<option value="' . esc_attr( $value ) . '">' . esc_html( $label ) . '</option>';
|
||||
}
|
||||
}
|
||||
|
||||
$out .= '</select>';
|
||||
$out .= '</div>';
|
||||
|
||||
return $out;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the column sorter controls. Safe for output.
|
||||
*
|
||||
* @param string $heading Heading text for the column. Optional.
|
||||
* @return string Markup for the column sorter controls.
|
||||
*/
|
||||
protected function build_sorter( $heading = '' ) {
|
||||
$out = '';
|
||||
$out .= '<span class="qm-th">';
|
||||
$out .= '<span class="qm-sort-heading">';
|
||||
|
||||
if ( '#' === $heading ) {
|
||||
$out .= '<span class="qm-screen-reader-text">' . esc_html__( 'Sequence', 'query-monitor' ) . '</span>';
|
||||
} elseif ( $heading ) {
|
||||
$out .= esc_html( $heading );
|
||||
}
|
||||
|
||||
$out .= '</span>';
|
||||
$out .= '<button class="qm-sort-controls" aria-label="' . esc_attr__( 'Sort data by this column', 'query-monitor' ) . '">';
|
||||
$out .= QueryMonitor::icon( 'arrow-down' );
|
||||
$out .= '</button>';
|
||||
$out .= '</span>';
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a toggle control. Safe for output.
|
||||
*
|
||||
* @return string Markup for the column sorter controls.
|
||||
*/
|
||||
protected static function build_toggler() {
|
||||
$out = '<button class="qm-toggle" data-on="+" data-off="-" aria-expanded="false" aria-label="' . esc_attr__( 'Toggle more information', 'query-monitor' ) . '"><span aria-hidden="true">+</span></button>';
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a filter trigger.
|
||||
*
|
||||
* @param string $target
|
||||
* @param string $filter
|
||||
* @param string $value
|
||||
* @param string $label
|
||||
* @return string
|
||||
*/
|
||||
protected static function build_filter_trigger( $target, $filter, $value, $label ) {
|
||||
return sprintf(
|
||||
'<button class="qm-filter-trigger" data-qm-target="%1$s" data-qm-filter="%2$s" data-qm-value="%3$s">%4$s%5$s</button>',
|
||||
esc_attr( $target ),
|
||||
esc_attr( $filter ),
|
||||
esc_attr( $value ),
|
||||
$label,
|
||||
QueryMonitor::icon( 'filter' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a link.
|
||||
*
|
||||
* @param string $href
|
||||
* @param string $label
|
||||
* @return string
|
||||
*/
|
||||
protected static function build_link( $href, $label ) {
|
||||
return sprintf(
|
||||
'<a href="%1$s" class="qm-link">%2$s%3$s</a>',
|
||||
esc_attr( $href ),
|
||||
$label,
|
||||
QueryMonitor::icon( 'external' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $args
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
protected function menu( array $args ) {
|
||||
|
||||
return array_merge( array(
|
||||
'id' => esc_attr( "query-monitor-{$this->collector->id}" ),
|
||||
'href' => esc_attr( '#' . $this->collector->id() ),
|
||||
), $args );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given SQL string in a nicely presented format. Safe for output.
|
||||
*
|
||||
* @param string $sql An SQL query string.
|
||||
* @return string The SQL formatted with markup.
|
||||
*/
|
||||
public static function format_sql( $sql ) {
|
||||
|
||||
$sql = str_replace( array( "\r\n", "\r", "\n", "\t" ), ' ', $sql );
|
||||
$sql = esc_html( $sql );
|
||||
$sql = trim( $sql );
|
||||
|
||||
$regex = 'ADD|AFTER|ALTER|AND|BEGIN|COMMIT|CREATE|DELETE|DESCRIBE|DO|DROP|ELSE|END|EXCEPT|EXPLAIN|FROM|GROUP|HAVING|INNER|INSERT|INTERSECT|LEFT|LIMIT|ON|OR|ORDER|OUTER|RENAME|REPLACE|RIGHT|ROLLBACK|SELECT|SET|SHOW|START|THEN|TRUNCATE|UNION|UPDATE|USE|USING|VALUES|WHEN|WHERE|XOR';
|
||||
$sql = preg_replace( '# (' . $regex . ') #', '<br> $1 ', $sql );
|
||||
|
||||
$keywords = '\b(?:ACTION|ADD|AFTER|AGAINST|ALTER|AND|ASC|AS|AUTO_INCREMENT|BEGIN|BETWEEN|BIGINT|BINARY|BIT|BLOB|BOOLEAN|BOOL|BREAK|BY|CASE|COLLATE|COLUMNS?|COMMIT|CONTINUE|CREATE|DATA(?:BASES?)?|DATE(?:TIME)?|DECIMAL|DECLARE|DEC|DEFAULT|DELAYED|DELETE|DESCRIBE|DESC|DISTINCT|DOUBLE|DO|DROP|DUPLICATE|ELSE|END|ENUM|EXCEPT|EXISTS|EXPLAIN|FIELDS|FLOAT|FORCE|FOREIGN|FOR|FROM|FULL|FUNCTION|GROUP|HAVING|IF|IGNORE|INDEX|INNER|INSERT|INTEGER|INTERSECT|INTERVAL|INTO|INT|IN|IS|JOIN|KEYS?|LEFT|LIKE|LIMIT|LONG(?:BLOB|TEXT)|MEDIUM(?:BLOB|INT|TEXT)|MATCH|MERGE|MIDDLEINT|NOT|NO|NULLIF|ON|ORDER|OR|OUTER|PRIMARY|PROC(?:EDURE)?|REGEXP|RENAME|REPLACE|RIGHT|RLIKE|ROLLBACK|SCHEMA|SELECT|SET|SHOW|SMALLINT|START|TABLES?|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TRUNCATE|UNION|UNIQUE|UNSIGNED|UPDATE|USE|USING|VALUES?|VAR(?:BINARY|CHAR)|WHEN|WHERE|WHILE|XOR)\b';
|
||||
$sql = preg_replace( '#' . $keywords . '#', '<b>$0</b>', $sql );
|
||||
|
||||
return '<code>' . $sql . '</code>';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given URL in a nicely presented format. Safe for output.
|
||||
*
|
||||
* @param string $url A URL.
|
||||
* @return string The URL formatted with markup.
|
||||
*/
|
||||
public static function format_url( $url ) {
|
||||
return str_replace( array( '?', '&' ), array( '<br>?', '<br>&' ), esc_html( $url ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a file path, name, and line number, or a clickable link to the file. Safe for output.
|
||||
*
|
||||
* @link https://querymonitor.com/blog/2019/02/clickable-stack-traces-and-function-names-in-query-monitor/
|
||||
*
|
||||
* @param string $text The display text, such as a function name or file name.
|
||||
* @param string $file The full file path and name.
|
||||
* @param int $line Optional. A line number, if appropriate.
|
||||
* @param bool $is_filename Optional. Is the text a plain file name? Default false.
|
||||
* @return string The fully formatted file link or file name, safe for output.
|
||||
*/
|
||||
public static function output_filename( $text, $file, $line = 0, $is_filename = false ) {
|
||||
if ( empty( $file ) ) {
|
||||
if ( $is_filename ) {
|
||||
return esc_html( $text );
|
||||
} else {
|
||||
return '<code>' . esc_html( $text ) . '</code>';
|
||||
}
|
||||
}
|
||||
|
||||
$link_line = $line ?: 1;
|
||||
|
||||
if ( ! self::has_clickable_links() ) {
|
||||
$fallback = QM_Util::standard_dir( $file, '' );
|
||||
if ( $line ) {
|
||||
$fallback .= ':' . $line;
|
||||
}
|
||||
if ( $is_filename ) {
|
||||
$return = esc_html( $text );
|
||||
} else {
|
||||
$return = '<code>' . esc_html( $text ) . '</code>';
|
||||
}
|
||||
if ( $fallback !== $text ) {
|
||||
$return .= '<br><span class="qm-info qm-supplemental">' . esc_html( $fallback ) . '</span>';
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
$map = self::get_file_path_map();
|
||||
|
||||
if ( ! empty( $map ) ) {
|
||||
foreach ( $map as $from => $to ) {
|
||||
$file = str_replace( $from, $to, $file );
|
||||
}
|
||||
}
|
||||
|
||||
/** @var string */
|
||||
$link_format = self::get_file_link_format();
|
||||
$link = sprintf( $link_format, rawurlencode( $file ), intval( $link_line ) );
|
||||
|
||||
if ( $is_filename ) {
|
||||
$format = '<a href="%1$s" class="qm-edit-link">%2$s%3$s</a>';
|
||||
} else {
|
||||
$format = '<a href="%1$s" class="qm-edit-link"><code>%2$s</code>%3$s</a>';
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
$format,
|
||||
esc_attr( $link ),
|
||||
esc_html( $text ),
|
||||
QueryMonitor::icon( 'edit' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a protocol URL for edit links in QM stack traces for various editors.
|
||||
*
|
||||
* @param string $editor The chosen code editor.
|
||||
* @param string|false $default_format A format to use if no editor is found.
|
||||
* @return string|false A protocol URL format or boolean false.
|
||||
*/
|
||||
public static function get_editor_file_link_format( $editor, $default_format ) {
|
||||
switch ( $editor ) {
|
||||
case 'phpstorm':
|
||||
return 'phpstorm://open?file=%f&line=%l';
|
||||
case 'vscode':
|
||||
return 'vscode://file/%f:%l';
|
||||
case 'atom':
|
||||
return 'atom://open/?url=file://%f&line=%l';
|
||||
case 'sublime':
|
||||
return 'subl://open/?url=file://%f&line=%l';
|
||||
case 'textmate':
|
||||
return 'txmt://open/?url=file://%f&line=%l';
|
||||
case 'netbeans':
|
||||
return 'nbopen://%f:%l';
|
||||
case 'nova':
|
||||
return 'nova://open?path=%f&line=%l';
|
||||
default:
|
||||
return $default_format;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|false
|
||||
*/
|
||||
public static function get_file_link_format() {
|
||||
if ( ! isset( self::$file_link_format ) ) {
|
||||
$format = ini_get( 'xdebug.file_link_format' );
|
||||
|
||||
if ( defined( 'QM_EDITOR_COOKIE' ) && isset( $_COOKIE[ QM_EDITOR_COOKIE ] ) ) {
|
||||
$format = self::get_editor_file_link_format(
|
||||
$_COOKIE[ QM_EDITOR_COOKIE ],
|
||||
$format
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the clickable file link format.
|
||||
*
|
||||
* @link https://querymonitor.com/blog/2019/02/clickable-stack-traces-and-function-names-in-query-monitor/
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param string|false $format The format of the clickable file link, or false if there is none.
|
||||
*/
|
||||
$format = apply_filters( 'qm/output/file_link_format', $format );
|
||||
if ( empty( $format ) ) {
|
||||
self::$file_link_format = false;
|
||||
} else {
|
||||
self::$file_link_format = str_replace( array( '%f', '%l' ), array( '%1$s', '%2$d' ), $format );
|
||||
}
|
||||
}
|
||||
|
||||
return self::$file_link_format;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public static function get_file_path_map() {
|
||||
/**
|
||||
* Filters the file path mapping for clickable file links.
|
||||
*
|
||||
* @link https://querymonitor.com/blog/2019/02/clickable-stack-traces-and-function-names-in-query-monitor/
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param array<string, string> $file_map Array of file path mappings. Keys are the source paths and values are the replacement paths.
|
||||
*/
|
||||
return apply_filters( 'qm/output/file_path_map', array() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function has_clickable_links() {
|
||||
return ( false !== self::get_file_link_format() );
|
||||
}
|
||||
|
||||
}
|
9
wp-content/plugins/query-monitor/output/Raw.php
Normal file
9
wp-content/plugins/query-monitor/output/Raw.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Abstract output class for raw output encoded as JSON.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
abstract class QM_Output_Raw extends QM_Output {
|
||||
}
|
73
wp-content/plugins/query-monitor/output/headers/overview.php
Normal file
73
wp-content/plugins/query-monitor/output/headers/overview.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* General overview output for HTTP headers.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Headers_Overview extends QM_Output_Headers {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Overview Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function get_output() {
|
||||
/** @var QM_Data_Overview $data */
|
||||
$data = $this->collector->get_data();
|
||||
$headers = array();
|
||||
|
||||
$headers['time_taken'] = number_format_i18n( $data->time_taken, 4 );
|
||||
$headers['time_usage'] = sprintf(
|
||||
/* translators: 1: Percentage of time limit used, 2: Time limit in seconds */
|
||||
__( '%1$s%% of %2$ss limit', 'query-monitor' ),
|
||||
number_format_i18n( $data->time_usage, 1 ),
|
||||
number_format_i18n( $data->time_limit )
|
||||
);
|
||||
|
||||
if ( ! empty( $data->memory ) ) {
|
||||
$headers['memory'] = sprintf(
|
||||
/* translators: %s: Memory used in megabytes */
|
||||
__( '%s MB', 'query-monitor' ),
|
||||
number_format_i18n( ( $data->memory / 1024 / 1024 ), 1 )
|
||||
);
|
||||
|
||||
if ( $data->memory_limit > 0 ) {
|
||||
$headers['memory_usage'] = sprintf(
|
||||
/* translators: 1: Percentage of memory limit used, 2: Memory limit in megabytes */
|
||||
__( '%1$s%% of %2$s MB server limit', 'query-monitor' ),
|
||||
number_format_i18n( $data->memory_usage, 1 ),
|
||||
number_format_i18n( $data->memory_limit / 1024 / 1024 )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $headers;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_headers_overview( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'overview' );
|
||||
if ( $collector ) {
|
||||
$output['overview'] = new QM_Output_Headers_Overview( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/headers', 'register_qm_output_headers_overview', 10, 2 );
|
@ -0,0 +1,86 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* PHP error output for HTTP headers.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Headers_PHP_Errors extends QM_Output_Headers {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_PHP_Errors Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function get_output() {
|
||||
/** @var QM_Data_PHP_Errors $data */
|
||||
$data = $this->collector->get_data();
|
||||
$headers = array();
|
||||
|
||||
if ( empty( $data->errors ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
|
||||
foreach ( $data->errors as $type => $errors ) {
|
||||
|
||||
foreach ( $errors as $error_key => $error ) {
|
||||
|
||||
$count++;
|
||||
|
||||
$stack = array();
|
||||
|
||||
if ( ! empty( $error['filtered_trace'] ) ) {
|
||||
$stack = array_column( $error['filtered_trace'], 'display' );
|
||||
}
|
||||
|
||||
$output_error = array(
|
||||
'key' => $error_key,
|
||||
'type' => $error['type'],
|
||||
'message' => $error['message'],
|
||||
'file' => QM_Util::standard_dir( $error['file'], '' ),
|
||||
'line' => $error['line'],
|
||||
'stack' => $stack,
|
||||
'component' => $error['component']->name,
|
||||
);
|
||||
|
||||
$key = sprintf( 'error-%d', $count );
|
||||
$headers[ $key ] = json_encode( $output_error );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge(
|
||||
array(
|
||||
'error-count' => $count,
|
||||
),
|
||||
$headers
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_headers_php_errors( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'php_errors' );
|
||||
if ( $collector ) {
|
||||
$output['php_errors'] = new QM_Output_Headers_PHP_Errors( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/headers', 'register_qm_output_headers_php_errors', 110, 2 );
|
@ -0,0 +1,53 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* HTTP redirects output for HTTP headers.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Headers_Redirects extends QM_Output_Headers {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Redirects Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function get_output() {
|
||||
/** @var QM_Data_Redirect $data */
|
||||
$data = $this->collector->get_data();
|
||||
$headers = array();
|
||||
|
||||
if ( ! isset( $data->trace ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$headers['Redirect-Trace'] = implode( ', ', $data->trace->get_stack() );
|
||||
return $headers;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_headers_redirects( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'redirects' );
|
||||
if ( $collector ) {
|
||||
$output['redirects'] = new QM_Output_Headers_Redirects( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/headers', 'register_qm_output_headers_redirects', 140, 2 );
|
139
wp-content/plugins/query-monitor/output/html/admin.php
Normal file
139
wp-content/plugins/query-monitor/output/html/admin.php
Normal file
@ -0,0 +1,139 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Admin screen output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Admin extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Admin Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 60 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Admin Screen', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
|
||||
/** @var QM_Data_Admin $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->current_screen ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3>get_current_screen()</h3>';
|
||||
|
||||
echo '<table>';
|
||||
echo '<thead class="qm-screen-reader-text">';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col">' . esc_html__( 'Property', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Value', 'query-monitor' ) . '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
echo '<tbody>';
|
||||
|
||||
foreach ( get_object_vars( $data->current_screen ) as $key => $value ) {
|
||||
echo '<tr>';
|
||||
echo '<th scope="row">' . esc_html( $key ) . '</th>';
|
||||
echo '<td>' . esc_html( $value ) . '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
echo '</table>';
|
||||
echo '</section>';
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'Globals', 'query-monitor' ) . '</h3>';
|
||||
echo '<table>';
|
||||
echo '<thead class="qm-screen-reader-text">';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col">' . esc_html__( 'Global Variable', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Value', 'query-monitor' ) . '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
echo '<tbody>';
|
||||
|
||||
$admin_globals = array(
|
||||
'pagenow',
|
||||
'typenow',
|
||||
'taxnow',
|
||||
'hook_suffix',
|
||||
);
|
||||
|
||||
foreach ( $admin_globals as $key ) {
|
||||
echo '<tr>';
|
||||
echo '<th scope="row">$' . esc_html( $key ) . '</th>';
|
||||
echo '<td>' . esc_html( $data->{$key} ) . '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
echo '</table>';
|
||||
echo '</section>';
|
||||
|
||||
if ( ! empty( $data->list_table ) ) {
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'List Table', 'query-monitor' ) . '</h3>';
|
||||
|
||||
if ( ! empty( $data->list_table['class_name'] ) ) {
|
||||
echo '<h4>' . esc_html__( 'Class:', 'query-monitor' ) . '</h4>';
|
||||
echo '<p><code>' . esc_html( $data->list_table['class_name'] ) . '</code></p>';
|
||||
}
|
||||
|
||||
echo '<h4>' . esc_html__( 'Column Filters:', 'query-monitor' ) . '</h4>';
|
||||
echo '<p><code>' . esc_html( $data->list_table['columns_filter'] ) . '</code></p>';
|
||||
echo '<p><code>' . esc_html( $data->list_table['sortables_filter'] ) . '</code></p>';
|
||||
echo '<h4>' . esc_html__( 'Column Action:', 'query-monitor' ) . '</h4>';
|
||||
echo '<p><code>' . esc_html( $data->list_table['column_action'] ) . '</code></p>';
|
||||
echo '</section>';
|
||||
|
||||
}
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_admin( array $output, QM_Collectors $collectors ) {
|
||||
if ( ! is_admin() ) {
|
||||
return $output;
|
||||
}
|
||||
$collector = QM_Collectors::get( 'response' );
|
||||
if ( $collector ) {
|
||||
$output['response'] = new QM_Output_Html_Admin( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_admin', 70, 2 );
|
288
wp-content/plugins/query-monitor/output/html/assets.php
Normal file
288
wp-content/plugins/query-monitor/output/html/assets.php
Normal file
@ -0,0 +1,288 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Scripts and styles output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
abstract class QM_Output_Html_Assets extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Assets Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 70 );
|
||||
add_filter( 'qm/output/menu_class', array( $this, 'admin_class' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
abstract public function get_type_labels();
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
|
||||
/** @var QM_Data_Assets */
|
||||
$data = $this->collector->get_data();
|
||||
$type_label = $this->get_type_labels();
|
||||
|
||||
if ( empty( $data->assets ) ) {
|
||||
$this->before_non_tabular_output();
|
||||
$notice = esc_html( $type_label['none'] );
|
||||
echo $this->build_notice( $notice ); // WPCS: XSS ok.
|
||||
$this->after_non_tabular_output();
|
||||
return;
|
||||
}
|
||||
|
||||
$position_labels = array(
|
||||
// @TODO translator comments or context:
|
||||
'missing' => __( 'Missing', 'query-monitor' ),
|
||||
'broken' => __( 'Missing Dependencies', 'query-monitor' ),
|
||||
'header' => __( 'Header', 'query-monitor' ),
|
||||
'footer' => __( 'Footer', 'query-monitor' ),
|
||||
);
|
||||
|
||||
$type = $this->collector->get_dependency_type();
|
||||
|
||||
$hosts = array(
|
||||
__( 'Other', 'query-monitor' ),
|
||||
);
|
||||
|
||||
$this->before_tabular_output();
|
||||
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col">' . esc_html__( 'Position', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Handle', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
$args = array(
|
||||
'prepend' => array(
|
||||
'local' => $data->host,
|
||||
),
|
||||
);
|
||||
echo $this->build_filter( $type . '-host', $hosts, __( 'Host', 'query-monitor' ), $args ); // WPCS: XSS ok.
|
||||
echo '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Source', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
echo $this->build_filter( $type . '-dependencies', $data->dependencies, __( 'Dependencies', 'query-monitor' ) ); // WPCS: XSS ok.
|
||||
echo '</th>';
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
echo $this->build_filter( $type . '-dependents', $data->dependents, __( 'Dependents', 'query-monitor' ) ); // WPCS: XSS ok.
|
||||
echo '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Version', 'query-monitor' ) . '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
|
||||
echo '<tbody>';
|
||||
|
||||
foreach ( $position_labels as $position => $label ) {
|
||||
if ( ! empty( $data->assets[ $position ] ) ) {
|
||||
foreach ( $data->assets[ $position ] as $handle => $asset ) {
|
||||
$this->dependency_row( $handle, $asset, $label );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
|
||||
echo '<tfoot>';
|
||||
|
||||
echo '<tr>';
|
||||
printf(
|
||||
'<td colspan="7">%1$s</td>',
|
||||
sprintf(
|
||||
esc_html( $type_label['total'] ),
|
||||
'<span class="qm-items-number">' . esc_html( number_format_i18n( $data->counts['total'] ) ) . '</span>'
|
||||
)
|
||||
);
|
||||
echo '</tr>';
|
||||
echo '</tfoot>';
|
||||
|
||||
$this->after_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $handle
|
||||
* @param array<string, mixed> $asset
|
||||
* @param string $label
|
||||
* @return void
|
||||
*/
|
||||
protected function dependency_row( $handle, array $asset, $label ) {
|
||||
/** @var QM_Data_Assets */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
$highlight_deps = array_map( array( $this, '_prefix_type' ), $asset['dependencies'] );
|
||||
$highlight_dependents = array_map( array( $this, '_prefix_type' ), $asset['dependents'] );
|
||||
|
||||
$dependencies_list = implode( ' ', $asset['dependencies'] );
|
||||
$dependents_list = implode( ' ', $asset['dependents'] );
|
||||
|
||||
$dependency_output = array();
|
||||
|
||||
foreach ( $asset['dependencies'] as $dep ) {
|
||||
if ( isset( $data->missing_dependencies[ $dep ] ) ) {
|
||||
$warning = QueryMonitor::icon( 'warning' );
|
||||
|
||||
$dependency_output[] = sprintf(
|
||||
'<span style="white-space:nowrap">%1$s%2$s</span>',
|
||||
$warning,
|
||||
sprintf(
|
||||
/* translators: %s: Name of missing script or style dependency */
|
||||
__( '%s (missing)', 'query-monitor' ),
|
||||
esc_html( $dep )
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$dependency_output[] = $dep;
|
||||
}
|
||||
}
|
||||
|
||||
$qm_host = ( $asset['local'] ) ? 'local' : __( 'Other', 'query-monitor' );
|
||||
|
||||
$class = '';
|
||||
|
||||
if ( $asset['warning'] ) {
|
||||
$class = 'qm-warn';
|
||||
}
|
||||
|
||||
$type = $this->collector->get_dependency_type();
|
||||
|
||||
echo '<tr data-qm-subject="' . esc_attr( $type . '-' . $handle ) . '" data-qm-' . esc_attr( $type ) . '-host="' . esc_attr( $qm_host ) . '" data-qm-' . esc_attr( $type ) . '-dependents="' . esc_attr( $dependents_list ) . '" data-qm-' . esc_attr( $type ) . '-dependencies="' . esc_attr( $dependencies_list ) . '" class="' . esc_attr( $class ) . '">';
|
||||
echo '<td class="qm-nowrap">';
|
||||
|
||||
$warning = QueryMonitor::icon( 'warning' );
|
||||
|
||||
if ( $asset['warning'] ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $warning;
|
||||
}
|
||||
|
||||
echo esc_html( $label );
|
||||
echo '</td>';
|
||||
|
||||
$host = $asset['host'];
|
||||
$parts = explode( '.', $host );
|
||||
|
||||
foreach ( $parts as $k => $part ) {
|
||||
if ( strlen( $part ) > 16 ) {
|
||||
$parts[ $k ] = substr( $parts[ $k ], 0, 6 ) . '…' . substr( $parts[ $k ], -6 );
|
||||
}
|
||||
}
|
||||
|
||||
$host = implode( '.', $parts );
|
||||
|
||||
if ( ! empty( $asset['port'] ) && ! empty( $asset['host'] ) ) {
|
||||
$host = "{$host}:{$asset['port']}";
|
||||
}
|
||||
|
||||
echo '<td class="qm-nowrap qm-ltr">' . esc_html( $handle ) . '</td>';
|
||||
echo '<td class="qm-nowrap qm-ltr">' . esc_html( $host ) . '</td>';
|
||||
echo '<td class="qm-ltr">';
|
||||
if ( $asset['source'] instanceof WP_Error ) {
|
||||
$error_data = $asset['source']->get_error_data();
|
||||
if ( $error_data && isset( $error_data['src'] ) ) {
|
||||
printf(
|
||||
'<span class="qm-warn">%1$s%2$s:</span><br>',
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
$warning,
|
||||
esc_html( $asset['source']->get_error_message() )
|
||||
);
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo self::build_link( $error_data['src'], esc_html( $error_data['src'] ) );
|
||||
} else {
|
||||
printf(
|
||||
'<span class="qm-warn">%1$s%2$s</span>',
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
$warning,
|
||||
esc_html( $asset['source']->get_error_message() )
|
||||
);
|
||||
}
|
||||
} elseif ( ! empty( $asset['source'] ) ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo self::build_link( $asset['source'], esc_html( $asset['display'] ) );
|
||||
}
|
||||
echo '</td>';
|
||||
echo '<td class="qm-ltr qm-highlighter" data-qm-highlight="' . esc_attr( implode( ' ', $highlight_deps ) ) . '">';
|
||||
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo implode( ', ', $dependency_output );
|
||||
|
||||
echo '</td>';
|
||||
echo '<td class="qm-ltr qm-highlighter" data-qm-highlight="' . esc_attr( implode( ' ', $highlight_dependents ) ) . '">' . implode( ', ', array_map( 'esc_html', $asset['dependents'] ) ) . '</td>';
|
||||
echo '<td class="qm-ltr">' . esc_html( $asset['ver'] ) . '</td>';
|
||||
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $val
|
||||
* @return string
|
||||
*/
|
||||
public function _prefix_type( $val ) {
|
||||
return $this->collector->get_dependency_type() . '-' . $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, string> $class
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function admin_class( array $class ) {
|
||||
/** @var QM_Data_Assets */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( ! empty( $data->broken ) || ! empty( $data->missing ) ) {
|
||||
$class[] = 'qm-error';
|
||||
}
|
||||
|
||||
return $class;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function admin_menu( array $menu ) {
|
||||
/** @var QM_Data_Assets */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->assets ) ) {
|
||||
return $menu;
|
||||
}
|
||||
|
||||
$type_label = $this->get_type_labels();
|
||||
$label = sprintf(
|
||||
$type_label['count'],
|
||||
number_format_i18n( $data->counts['total'] )
|
||||
);
|
||||
|
||||
$args = array(
|
||||
'title' => esc_html( $label ),
|
||||
'id' => esc_attr( "query-monitor-{$this->collector->id}" ),
|
||||
'href' => esc_attr( '#' . $this->collector->id() ),
|
||||
);
|
||||
|
||||
if ( ! empty( $data->broken ) || ! empty( $data->missing ) ) {
|
||||
$args['meta']['classname'] = 'qm-error';
|
||||
}
|
||||
|
||||
$id = $this->collector->id();
|
||||
$menu[ $id ] = $this->menu( $args );
|
||||
|
||||
return $menu;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Enqueued scripts output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Assets_Scripts extends QM_Output_Html_Assets {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Assets_Scripts Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Scripts', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function get_type_labels() {
|
||||
return array(
|
||||
/* translators: %s: Total number of enqueued scripts */
|
||||
'total' => _x( 'Total: %s', 'Enqueued scripts', 'query-monitor' ),
|
||||
'plural' => __( 'Scripts', 'query-monitor' ),
|
||||
/* translators: %s: Total number of enqueued scripts */
|
||||
'count' => _x( 'Scripts (%s)', 'Enqueued scripts', 'query-monitor' ),
|
||||
'none' => __( 'No JavaScript files were enqueued.', 'query-monitor' ),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_assets_scripts( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'assets_scripts' );
|
||||
if ( $collector ) {
|
||||
$output['assets_scripts'] = new QM_Output_Html_Assets_Scripts( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_assets_scripts', 80, 2 );
|
@ -0,0 +1,57 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Enqueued styles output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Assets_Styles extends QM_Output_Html_Assets {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Assets_Styles Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Styles', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function get_type_labels() {
|
||||
return array(
|
||||
/* translators: %s: Total number of enqueued styles */
|
||||
'total' => _x( 'Total: %s', 'Enqueued styles', 'query-monitor' ),
|
||||
'plural' => __( 'Styles', 'query-monitor' ),
|
||||
/* translators: %s: Total number of enqueued styles */
|
||||
'count' => _x( 'Styles (%s)', 'Enqueued styles', 'query-monitor' ),
|
||||
'none' => __( 'No CSS files were enqueued.', 'query-monitor' ),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_assets_styles( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'assets_styles' );
|
||||
if ( $collector ) {
|
||||
$output['assets_styles'] = new QM_Output_Html_Assets_Styles( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_assets_styles', 80, 2 );
|
360
wp-content/plugins/query-monitor/output/html/block_editor.php
Normal file
360
wp-content/plugins/query-monitor/output/html/block_editor.php
Normal file
@ -0,0 +1,360 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Block editor data output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Block_Editor extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Block_Editor Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 55 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Blocks', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_Block_Editor */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->block_editor_enabled ) || empty( $data->post_blocks ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $data->post_has_blocks ) {
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
$notice = __( 'This post contains no blocks.', 'query-monitor' );
|
||||
echo $this->build_notice( $notice ); // WPCS: XSS ok.
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->before_tabular_output();
|
||||
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col">#</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Block Name', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Attributes', 'query-monitor' ) . '</th>';
|
||||
|
||||
if ( $data->has_block_context ) {
|
||||
echo '<th scope="col">' . esc_html__( 'Context', 'query-monitor' ) . '</th>';
|
||||
}
|
||||
|
||||
echo '<th scope="col">' . esc_html__( 'Render Callback', 'query-monitor' ) . '</th>';
|
||||
|
||||
if ( $data->has_block_timing ) {
|
||||
echo '<th scope="col" class="qm-num">' . esc_html__( 'Render Time', 'query-monitor' ) . '</th>';
|
||||
}
|
||||
|
||||
echo '<th scope="col">' . esc_html__( 'Inner HTML', 'query-monitor' ) . '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
|
||||
echo '<tbody>';
|
||||
|
||||
foreach ( $data->post_blocks as $i => $block ) {
|
||||
self::render_block( ++$i, $block, $data );
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
|
||||
echo '<tfoot>';
|
||||
echo '<tr>';
|
||||
|
||||
$colspan = 5;
|
||||
|
||||
if ( $data->has_block_context ) {
|
||||
$colspan++;
|
||||
}
|
||||
|
||||
if ( $data->has_block_timing ) {
|
||||
$colspan++;
|
||||
}
|
||||
|
||||
printf(
|
||||
'<td colspan="%1$d">%2$s</td>',
|
||||
intval( $colspan ),
|
||||
sprintf(
|
||||
/* translators: %s: Total number of content blocks used */
|
||||
esc_html( _nx( 'Total: %s', 'Total: %s', $data->total_blocks, 'Content blocks used', 'query-monitor' ) ),
|
||||
'<span class="qm-items-number">' . esc_html( number_format_i18n( $data->total_blocks ) ) . '</span>'
|
||||
)
|
||||
);
|
||||
echo '</tr>';
|
||||
echo '</tfoot>';
|
||||
|
||||
$this->after_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|string $i
|
||||
* @param array<string, mixed> $block
|
||||
* @param QM_Data_Block_Editor $data
|
||||
* @return void
|
||||
*/
|
||||
protected static function render_block( $i, array $block, QM_Data_Block_Editor $data ) {
|
||||
$block_error = false;
|
||||
$row_class = '';
|
||||
$referenced_post = null;
|
||||
$referenced_type = null;
|
||||
$referenced_template_part = null;
|
||||
$referenced_pto = null;
|
||||
$error_message = null;
|
||||
|
||||
if ( 'core/block' === $block['blockName'] && ! empty( $block['attrs']['ref'] ) ) {
|
||||
$referenced_post = get_post( $block['attrs']['ref'] );
|
||||
|
||||
if ( ! $referenced_post ) {
|
||||
$block_error = true;
|
||||
$error_message = esc_html__( 'Referenced block does not exist.', 'query-monitor' );
|
||||
} else {
|
||||
$referenced_type = $referenced_post->post_type;
|
||||
$referenced_pto = get_post_type_object( $referenced_type );
|
||||
if ( 'wp_block' !== $referenced_type ) {
|
||||
$block_error = true;
|
||||
$error_message = sprintf(
|
||||
/* translators: %1$s: Erroneous post type name, %2$s: WordPress block post type name */
|
||||
esc_html__( 'Referenced post is of type %1$s instead of %2$s.', 'query-monitor' ),
|
||||
'<code>' . esc_html( $referenced_type ) . '</code>',
|
||||
'<code>wp_block</code>'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$media_blocks = array(
|
||||
'core/audio' => 'id',
|
||||
'core/cover' => 'id',
|
||||
'core/cover-image' => 'id',
|
||||
'core/file' => 'id',
|
||||
'core/image' => 'id',
|
||||
'core/media-text' => 'mediaId', // (╯°□°)╯︵ ┻━┻
|
||||
'core/video' => 'id',
|
||||
);
|
||||
|
||||
if ( isset( $media_blocks[ $block['blockName'] ] ) && is_array( $block['attrs'] ) && ! empty( $block['attrs'][ $media_blocks[ $block['blockName'] ] ] ) ) {
|
||||
$referenced_post = get_post( $block['attrs'][ $media_blocks[ $block['blockName'] ] ] );
|
||||
|
||||
if ( ! $referenced_post ) {
|
||||
$block_error = true;
|
||||
$error_message = esc_html__( 'Referenced media does not exist.', 'query-monitor' );
|
||||
} else {
|
||||
$referenced_type = $referenced_post->post_type;
|
||||
$referenced_pto = get_post_type_object( $referenced_type );
|
||||
if ( 'attachment' !== $referenced_type ) {
|
||||
$block_error = true;
|
||||
$error_message = sprintf(
|
||||
/* translators: %1$s: Erroneous post type name, %2$s: WordPress attachment post type name */
|
||||
esc_html__( 'Referenced media is of type %1$s instead of %2$s.', 'query-monitor' ),
|
||||
'<code>' . esc_html( $referenced_type ) . '</code>',
|
||||
'<code>attachment</code>'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$template_part_blocks = array(
|
||||
'core/template-part' => true,
|
||||
);
|
||||
|
||||
if ( isset( $template_part_blocks[ $block['blockName'] ] ) && is_array( $block['attrs'] ) && ! empty( $block['attrs']['slug'] ) && ! empty( $block['attrs']['theme'] ) ) {
|
||||
$referenced_template_part = sprintf(
|
||||
'%s//%s',
|
||||
$block['attrs']['theme'],
|
||||
$block['attrs']['slug']
|
||||
);
|
||||
$referenced_pto = get_post_type_object( 'wp_template_part' );
|
||||
}
|
||||
|
||||
if ( $block_error ) {
|
||||
$row_class = 'qm-warn';
|
||||
}
|
||||
|
||||
echo '<tr class="' . esc_attr( $row_class ) . '">';
|
||||
|
||||
echo '<th scope="row" class="qm-row-num qm-num"><span class="qm-sticky">' . esc_html( $i ) . '</span></th>';
|
||||
|
||||
echo '<td class="qm-row-block-name"><span class="qm-sticky">';
|
||||
|
||||
if ( $block['blockName'] ) {
|
||||
echo esc_html( $block['blockName'] );
|
||||
} else {
|
||||
echo '<em>' . esc_html__( 'None (Classic block)', 'query-monitor' ) . '</em>';
|
||||
}
|
||||
|
||||
if ( $error_message ) {
|
||||
echo '<br>';
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo QueryMonitor::icon( 'warning' );
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $error_message;
|
||||
}
|
||||
|
||||
if ( ! empty( $referenced_post ) && ! empty( $referenced_pto ) ) {
|
||||
echo '<br>';
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo self::build_link( get_edit_post_link( $referenced_post ), esc_html( $referenced_pto->labels->edit_item ) );
|
||||
}
|
||||
|
||||
if ( ! empty( $referenced_template_part ) ) {
|
||||
echo '<br>';
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo self::build_link( QM_Util::get_site_editor_url( $referenced_template_part ), esc_html( $referenced_pto->labels->edit_item ) );
|
||||
}
|
||||
|
||||
echo '</span></td>';
|
||||
|
||||
echo '<td class="qm-row-block-attrs">';
|
||||
if ( $block['attrs'] && is_array( $block['attrs'] ) ) {
|
||||
echo '<pre class="qm-pre-wrap"><code>' . esc_html( QM_Util::json_format( $block['attrs'] ) ) . '</code></pre>';
|
||||
}
|
||||
echo '</td>';
|
||||
|
||||
if ( $data->has_block_context ) {
|
||||
echo '<td class="qm-row-block-context">';
|
||||
if ( isset( $block['context'] ) ) {
|
||||
echo '<pre class="qm-pre-wrap"><code>' . esc_html( QM_Util::json_format( $block['context'] ) ) . '</code></pre>';
|
||||
}
|
||||
echo '</td>';
|
||||
}
|
||||
|
||||
if ( isset( $block['callback']['error'] ) ) {
|
||||
$class = ' qm-warn';
|
||||
} else {
|
||||
$class = '';
|
||||
}
|
||||
|
||||
if ( $block['dynamic'] ) {
|
||||
if ( isset( $block['callback']['file'] ) ) {
|
||||
if ( self::has_clickable_links() ) {
|
||||
echo '<td class="qm-nowrap qm-ltr' . esc_attr( $class ) . '">';
|
||||
echo self::output_filename( $block['callback']['name'], $block['callback']['file'], $block['callback']['line'] ); // WPCS: XSS ok.
|
||||
echo '</td>';
|
||||
} else {
|
||||
echo '<td class="qm-nowrap qm-ltr qm-has-toggle' . esc_attr( $class ) . '">';
|
||||
echo self::build_toggler(); // WPCS: XSS ok;
|
||||
echo '<ol>';
|
||||
echo '<li>';
|
||||
echo self::output_filename( $block['callback']['name'], $block['callback']['file'], $block['callback']['line'] ); // WPCS: XSS ok.
|
||||
echo '</li>';
|
||||
echo '</ol></td>';
|
||||
}
|
||||
} else {
|
||||
echo '<td class="qm-ltr qm-nowrap' . esc_attr( $class ) . '">';
|
||||
echo '<code>' . esc_html( $block['callback']['name'] ) . '</code>';
|
||||
|
||||
if ( isset( $block['callback']['error'] ) ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<br>' . QueryMonitor::icon( 'warning' );
|
||||
echo esc_html( sprintf(
|
||||
/* translators: %s: Error message text */
|
||||
__( 'Error: %s', 'query-monitor' ),
|
||||
$block['callback']['error']->get_error_message()
|
||||
) );
|
||||
}
|
||||
|
||||
echo '</td>';
|
||||
}
|
||||
|
||||
if ( $data->has_block_timing ) {
|
||||
echo '<td class="qm-num">';
|
||||
if ( isset( $block['timing'] ) ) {
|
||||
echo esc_html( number_format_i18n( $block['timing'], 4 ) );
|
||||
}
|
||||
echo '</td>';
|
||||
}
|
||||
} else {
|
||||
echo '<td></td>';
|
||||
|
||||
if ( $data->has_block_timing ) {
|
||||
echo '<td></td>';
|
||||
}
|
||||
}
|
||||
|
||||
$inner_html = $block['innerHTML'];
|
||||
|
||||
if ( $block['size'] > 300 ) {
|
||||
echo '<td class="qm-ltr qm-has-toggle qm-row-block-html">';
|
||||
echo self::build_toggler(); // WPCS: XSS ok;
|
||||
echo '<div class="qm-inverse-toggled"><pre class="qm-pre-wrap"><code>';
|
||||
echo esc_html( substr( $inner_html, 0, 200 ) ) . ' …';
|
||||
echo '</code></pre></div>';
|
||||
echo '<div class="qm-toggled"><pre class="qm-pre-wrap"><code>';
|
||||
echo esc_html( $inner_html );
|
||||
echo '</code></pre></div>';
|
||||
echo '</td>';
|
||||
} else {
|
||||
echo '<td class="qm-row-block-html"><pre class="qm-pre-wrap"><code>';
|
||||
echo esc_html( $inner_html );
|
||||
echo '</code></pre></td>';
|
||||
}
|
||||
|
||||
echo '</tr>';
|
||||
|
||||
if ( ! empty( $block['innerBlocks'] ) ) {
|
||||
foreach ( $block['innerBlocks'] as $j => $inner_block ) {
|
||||
$x = ++$j;
|
||||
self::render_block( "{$i}.{$x}", $inner_block, $data );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function admin_menu( array $menu ) {
|
||||
/** @var QM_Data_Block_Editor */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->block_editor_enabled ) || empty( $data->post_blocks ) ) {
|
||||
return $menu;
|
||||
}
|
||||
|
||||
$menu[ $this->collector->id() ] = $this->menu( array(
|
||||
'title' => esc_html__( 'Blocks', 'query-monitor' ),
|
||||
) );
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_block_editor( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'block_editor' );
|
||||
if ( $collector ) {
|
||||
$output['block_editor'] = new QM_Output_Html_Block_Editor( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_block_editor', 60, 2 );
|
242
wp-content/plugins/query-monitor/output/html/caps.php
Normal file
242
wp-content/plugins/query-monitor/output/html/caps.php
Normal file
@ -0,0 +1,242 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* User capability checks output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Caps extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Caps Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 105 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Capability Checks', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
$collector = $this->collector;
|
||||
|
||||
if ( ! $collector::enabled() ) {
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
echo '<section>';
|
||||
echo '<div class="qm-notice">';
|
||||
echo '<p>';
|
||||
printf(
|
||||
/* translators: %s: Configuration file name. */
|
||||
esc_html__( 'For performance reasons, this panel is not enabled by default. To enable it, add the following code to your %s file:', 'query-monitor' ),
|
||||
'<code>wp-config.php</code>'
|
||||
);
|
||||
echo '</p>';
|
||||
echo "<p><code>define( 'QM_ENABLE_CAPS_PANEL', true );</code></p>";
|
||||
echo '</div>';
|
||||
echo '</section>';
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var QM_Data_Caps */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( ! empty( $data->caps ) ) {
|
||||
$this->before_tabular_output();
|
||||
|
||||
$results = array(
|
||||
'true',
|
||||
'false',
|
||||
);
|
||||
$parts = $data->parts;
|
||||
$components = $data->components;
|
||||
|
||||
usort( $parts, 'strcasecmp' );
|
||||
usort( $components, 'strcasecmp' );
|
||||
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
echo $this->build_filter( 'name', $parts, __( 'Capability Check', 'query-monitor' ) ); // WPCS: XSS ok;
|
||||
echo '</th>';
|
||||
|
||||
$users = $data->users;
|
||||
|
||||
sort( $users );
|
||||
|
||||
echo '<th scope="col" class="qm-filterable-column qm-num">';
|
||||
echo $this->build_filter( 'user', $users, __( 'User', 'query-monitor' ) ); // WPCS: XSS ok;
|
||||
echo '</th>';
|
||||
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
echo $this->build_filter( 'result', $results, __( 'Result', 'query-monitor' ) ); // WPCS: XSS ok;
|
||||
echo '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Caller', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
echo $this->build_filter( 'component', $components, __( 'Component', 'query-monitor' ) ); // WPCS: XSS ok.
|
||||
echo '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
|
||||
echo '<tbody>';
|
||||
|
||||
foreach ( $data->caps as $row ) {
|
||||
$component = $row['component'];
|
||||
|
||||
$row_attr = array();
|
||||
$row_attr['data-qm-name'] = implode( ' ', $row['parts'] );
|
||||
$row_attr['data-qm-user'] = $row['user'];
|
||||
$row_attr['data-qm-component'] = $component->name;
|
||||
$row_attr['data-qm-result'] = ( $row['result'] ) ? 'true' : 'false';
|
||||
|
||||
if ( 'core' !== $component->context ) {
|
||||
$row_attr['data-qm-component'] .= ' non-core';
|
||||
}
|
||||
|
||||
if ( '' === $row['name'] ) {
|
||||
$row_attr['class'] = 'qm-warn';
|
||||
}
|
||||
|
||||
$attr = '';
|
||||
|
||||
foreach ( $row_attr as $a => $v ) {
|
||||
$attr .= ' ' . $a . '="' . esc_attr( $v ) . '"';
|
||||
}
|
||||
|
||||
printf( // WPCS: XSS ok.
|
||||
'<tr %s>',
|
||||
$attr
|
||||
);
|
||||
|
||||
$name = esc_html( $row['name'] );
|
||||
|
||||
if ( ! empty( $row['args'] ) ) {
|
||||
foreach ( $row['args'] as $arg ) {
|
||||
$name .= ', ' . esc_html( QM_Util::display_variable( $arg ) );
|
||||
}
|
||||
}
|
||||
|
||||
printf( // WPCS: XSS ok.
|
||||
'<td class="qm-ltr qm-nowrap"><code>%s</code></td>',
|
||||
$name
|
||||
);
|
||||
|
||||
printf(
|
||||
'<td class="qm-num">%s</td>',
|
||||
esc_html( $row['user'] )
|
||||
);
|
||||
|
||||
$result = ( $row['result'] ) ? '<span class="qm-true">true ✓</span>' : 'false';
|
||||
printf( // WPCS: XSS ok.
|
||||
'<td class="qm-nowrap">%s</td>',
|
||||
$result
|
||||
);
|
||||
|
||||
$stack = array();
|
||||
|
||||
foreach ( $row['filtered_trace'] as $frame ) {
|
||||
$stack[] = self::output_filename( $frame['display'], $frame['calling_file'], $frame['calling_line'] );
|
||||
}
|
||||
|
||||
$caller = array_shift( $stack );
|
||||
|
||||
echo '<td class="qm-has-toggle qm-nowrap qm-ltr">';
|
||||
|
||||
if ( ! empty( $stack ) ) {
|
||||
echo self::build_toggler(); // WPCS: XSS ok;
|
||||
}
|
||||
|
||||
echo '<ol>';
|
||||
|
||||
echo "<li>{$caller}</li>"; // WPCS: XSS ok.
|
||||
|
||||
if ( ! empty( $stack ) ) {
|
||||
echo '<div class="qm-toggled"><li>' . implode( '</li><li>', $stack ) . '</li></div>'; // WPCS: XSS ok.
|
||||
}
|
||||
|
||||
echo '</ol></td>';
|
||||
|
||||
printf(
|
||||
'<td class="qm-nowrap">%s</td>',
|
||||
esc_html( $component->name )
|
||||
);
|
||||
|
||||
echo '</tr>';
|
||||
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
|
||||
echo '<tfoot>';
|
||||
|
||||
$count = count( $data->caps );
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td colspan="5">';
|
||||
printf(
|
||||
/* translators: %s: Number of user capability checks */
|
||||
esc_html( _nx( 'Total: %s', 'Total: %s', $count, 'User capability checks', 'query-monitor' ) ),
|
||||
'<span class="qm-items-number">' . esc_html( number_format_i18n( $count ) ) . '</span>'
|
||||
);
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
echo '</tfoot>';
|
||||
|
||||
$this->after_tabular_output();
|
||||
} else {
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
$notice = __( 'No capability checks were recorded.', 'query-monitor' );
|
||||
echo $this->build_notice( $notice ); // WPCS: XSS ok.
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function admin_menu( array $menu ) {
|
||||
$menu[ $this->collector->id() ] = $this->menu( array(
|
||||
'title' => $this->name(),
|
||||
) );
|
||||
return $menu;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_caps( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'caps' );
|
||||
if ( $collector ) {
|
||||
$output['caps'] = new QM_Output_Html_Caps( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_caps', 105, 2 );
|
131
wp-content/plugins/query-monitor/output/html/conditionals.php
Normal file
131
wp-content/plugins/query-monitor/output/html/conditionals.php
Normal file
@ -0,0 +1,131 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Template conditionals output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Conditionals extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Conditionals Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 1000 );
|
||||
add_filter( 'qm/output/panel_menus', array( $this, 'panel_menu' ), 1000 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Conditionals', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_Conditionals $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'True Conditionals', 'query-monitor' ) . '</h3>';
|
||||
|
||||
echo '<ul>';
|
||||
foreach ( $data->conds['true'] as $cond ) {
|
||||
echo '<li class="qm-ltr qm-true"><code>' . esc_html( $cond ) . '() </code></li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
|
||||
echo '</section>';
|
||||
echo '</div>';
|
||||
|
||||
echo '<div class="qm-boxed">';
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'False Conditionals', 'query-monitor' ) . '</h3>';
|
||||
|
||||
echo '<ul>';
|
||||
foreach ( $data->conds['false'] as $cond ) {
|
||||
echo '<li class="qm-ltr qm-false"><code>' . esc_html( $cond ) . '() </code></li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
|
||||
echo '</section>';
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function admin_menu( array $menu ) {
|
||||
/** @var QM_Data_Conditionals $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
foreach ( $data->conds['true'] as $cond ) {
|
||||
$id = $this->collector->id() . '-' . $cond;
|
||||
$menu[ $id ] = $this->menu( array(
|
||||
'title' => esc_html( $cond . '()' ),
|
||||
'id' => 'query-monitor-conditionals-' . esc_attr( $cond ),
|
||||
'meta' => array(
|
||||
'classname' => 'qm-true qm-ltr',
|
||||
),
|
||||
) );
|
||||
}
|
||||
|
||||
return $menu;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function panel_menu( array $menu ) {
|
||||
/** @var QM_Data_Conditionals $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
foreach ( $data->conds['true'] as $cond ) {
|
||||
$id = $this->collector->id() . '-' . $cond;
|
||||
unset( $menu[ $id ] );
|
||||
}
|
||||
|
||||
$menu[ $this->collector->id() ] = $this->menu( array(
|
||||
'title' => esc_html__( 'Conditionals', 'query-monitor' ),
|
||||
'id' => 'query-monitor-conditionals',
|
||||
) );
|
||||
|
||||
return $menu;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_conditionals( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'conditionals' );
|
||||
if ( $collector ) {
|
||||
$output['conditionals'] = new QM_Output_Html_Conditionals( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_conditionals', 50, 2 );
|
154
wp-content/plugins/query-monitor/output/html/db_callers.php
Normal file
154
wp-content/plugins/query-monitor/output/html/db_callers.php
Normal file
@ -0,0 +1,154 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Database query calling function output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_DB_Callers extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_DB_Callers Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/panel_menus', array( $this, 'panel_menu' ), 30 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Queries by Caller', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_DB_Callers $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->types ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$total_time = 0;
|
||||
|
||||
if ( ! empty( $data->times ) ) {
|
||||
$this->before_tabular_output();
|
||||
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col">' . esc_html__( 'Caller', 'query-monitor' ) . '</th>';
|
||||
|
||||
foreach ( $data->types as $type_name => $type_count ) {
|
||||
echo '<th scope="col" class="qm-num qm-ltr qm-sortable-column" role="columnheader">';
|
||||
echo $this->build_sorter( $type_name ); // WPCS: XSS ok;
|
||||
echo '</th>';
|
||||
}
|
||||
|
||||
echo '<th scope="col" class="qm-num qm-sorted-desc qm-sortable-column" role="columnheader" aria-sort="descending">';
|
||||
echo $this->build_sorter( __( 'Time', 'query-monitor' ) ); // WPCS: XSS ok;
|
||||
echo '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
|
||||
echo '<tbody>';
|
||||
|
||||
foreach ( $data->times as $row ) {
|
||||
$total_time += $row['ltime'];
|
||||
$stime = number_format_i18n( $row['ltime'], 4 );
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td class="qm-ltr">';
|
||||
echo self::build_filter_trigger( 'db_queries', 'caller', $row['caller'], '<code>' . esc_html( $row['caller'] ) . '</code>' ); // WPCS: XSS ok;
|
||||
echo '</td>';
|
||||
|
||||
foreach ( $data->types as $type_name => $type_count ) {
|
||||
if ( isset( $row['types'][ $type_name ] ) ) {
|
||||
echo "<td class='qm-num'>" . esc_html( number_format_i18n( $row['types'][ $type_name ] ) ) . '</td>';
|
||||
} else {
|
||||
echo "<td class='qm-num'></td>";
|
||||
}
|
||||
}
|
||||
|
||||
echo '<td class="qm-num" data-qm-sort-weight="' . esc_attr( (string) $row['ltime'] ) . '">' . esc_html( $stime ) . '</td>';
|
||||
echo '</tr>';
|
||||
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
echo '<tfoot>';
|
||||
|
||||
$total_stime = number_format_i18n( $total_time, 4 );
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td></td>';
|
||||
|
||||
foreach ( $data->types as $type_name => $type_count ) {
|
||||
echo '<td class="qm-num">' . esc_html( number_format_i18n( $type_count ) ) . '</td>';
|
||||
}
|
||||
|
||||
echo '<td class="qm-num">' . esc_html( $total_stime ) . '</td>';
|
||||
echo '</tr>';
|
||||
|
||||
echo '</tfoot>';
|
||||
|
||||
$this->after_tabular_output();
|
||||
} else {
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
echo '<div class="qm-none">';
|
||||
echo '<p>' . esc_html__( 'None', 'query-monitor' ) . '</p>';
|
||||
echo '</div>';
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function panel_menu( array $menu ) {
|
||||
/** @var QM_Collector_DB_Queries|null $dbq */
|
||||
$dbq = QM_Collectors::get( 'db_queries' );
|
||||
|
||||
if ( $dbq ) {
|
||||
/** @var QM_Data_DB_Queries $dbq_data */
|
||||
$dbq_data = $dbq->get_data();
|
||||
if ( ! empty( $dbq_data->times ) ) {
|
||||
$menu['qm-db_queries']['children'][] = $this->menu( array(
|
||||
'title' => esc_html__( 'Queries by Caller', 'query-monitor' ),
|
||||
) );
|
||||
}
|
||||
}
|
||||
return $menu;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_db_callers( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'db_callers' );
|
||||
if ( $collector ) {
|
||||
$output['db_callers'] = new QM_Output_Html_DB_Callers( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_db_callers', 30, 2 );
|
150
wp-content/plugins/query-monitor/output/html/db_components.php
Normal file
150
wp-content/plugins/query-monitor/output/html/db_components.php
Normal file
@ -0,0 +1,150 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Database query calling component output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_DB_Components extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_DB_Components Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/panel_menus', array( $this, 'panel_menu' ), 40 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Queries by Component', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_DB_Components $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->types ) || empty( $data->times ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$total_time = 0;
|
||||
|
||||
$this->before_tabular_output();
|
||||
|
||||
echo '<thead>';
|
||||
|
||||
echo '<tr>';
|
||||
echo '<th scope="col">' . esc_html__( 'Component', 'query-monitor' ) . '</th>';
|
||||
|
||||
foreach ( $data->types as $type_name => $type_count ) {
|
||||
echo '<th scope="col" class="qm-num qm-sortable-column" role="columnheader">';
|
||||
echo $this->build_sorter( $type_name ); // WPCS: XSS ok;
|
||||
echo '</th>';
|
||||
}
|
||||
|
||||
echo '<th scope="col" class="qm-num qm-sorted-desc qm-sortable-column" role="columnheader" aria-sort="descending">';
|
||||
echo $this->build_sorter( __( 'Time', 'query-monitor' ) ); // WPCS: XSS ok;
|
||||
echo '</th>';
|
||||
echo '</tr>';
|
||||
|
||||
echo '</thead>';
|
||||
|
||||
echo '<tbody>';
|
||||
|
||||
foreach ( $data->times as $row ) {
|
||||
$total_time += $row['ltime'];
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td class="qm-row-component">';
|
||||
echo self::build_filter_trigger( 'db_queries', 'component', $row['component'], esc_html( $row['component'] ) ); // WPCS: XSS ok;
|
||||
|
||||
foreach ( $data->types as $type_name => $type_count ) {
|
||||
if ( isset( $row['types'][ $type_name ] ) ) {
|
||||
echo '<td class="qm-num">' . esc_html( number_format_i18n( $row['types'][ $type_name ] ) ) . '</td>';
|
||||
} else {
|
||||
echo '<td class="qm-num"> </td>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '<td class="qm-num" data-qm-sort-weight="' . esc_attr( (string) $row['ltime'] ) . '">' . esc_html( number_format_i18n( $row['ltime'], 4 ) ) . '</td>';
|
||||
echo '</tr>';
|
||||
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
echo '<tfoot>';
|
||||
|
||||
$total_stime = number_format_i18n( $total_time, 4 );
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td> </td>';
|
||||
|
||||
foreach ( $data->types as $type_name => $type_count ) {
|
||||
echo '<td class="qm-num">' . esc_html( number_format_i18n( $type_count ) ) . '</td>';
|
||||
}
|
||||
|
||||
echo '<td class="qm-num">' . esc_html( $total_stime ) . '</td>';
|
||||
echo '</tr>';
|
||||
echo '</tfoot>';
|
||||
|
||||
$this->after_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function panel_menu( array $menu ) {
|
||||
/** @var QM_Data_DB_Components $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->types ) || empty( $data->times ) ) {
|
||||
return $menu;
|
||||
}
|
||||
|
||||
/** @var QM_Collector_DB_Queries|null $dbq */
|
||||
$dbq = QM_Collectors::get( 'db_queries' );
|
||||
|
||||
if ( $dbq ) {
|
||||
/** @var QM_Data_DB_Queries $dbq_data */
|
||||
$dbq_data = $dbq->get_data();
|
||||
if ( ! empty( $dbq_data->component_times ) ) {
|
||||
$menu['qm-db_queries']['children'][] = $this->menu( array(
|
||||
'title' => esc_html__( 'Queries by Component', 'query-monitor' ),
|
||||
) );
|
||||
}
|
||||
}
|
||||
return $menu;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_db_components( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'db_components' );
|
||||
if ( $collector ) {
|
||||
$output['db_components'] = new QM_Output_Html_DB_Components( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_db_components', 40, 2 );
|
193
wp-content/plugins/query-monitor/output/html/db_dupes.php
Normal file
193
wp-content/plugins/query-monitor/output/html/db_dupes.php
Normal file
@ -0,0 +1,193 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Duplicate database query output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_DB_Dupes extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_DB_Dupes Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 45 );
|
||||
add_filter( 'qm/output/panel_menus', array( $this, 'panel_menu' ), 25 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Duplicate Queries', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_DB_Dupes $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->dupes ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->before_tabular_output();
|
||||
|
||||
echo '<thead>';
|
||||
|
||||
echo '<tr>';
|
||||
echo '<th scope="col">' . esc_html__( 'Query', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col" class="qm-num">' . esc_html__( 'Count', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col" class="qm-num">' . esc_html__( 'Time', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Callers', 'query-monitor' ) . '</th>';
|
||||
if ( ! empty( $data->dupe_components ) ) {
|
||||
echo '<th scope="col">' . esc_html__( 'Components', 'query-monitor' ) . '</th>';
|
||||
}
|
||||
echo '<th scope="col">' . esc_html__( 'Potential Troublemakers', 'query-monitor' ) . '</th>';
|
||||
echo '</tr>';
|
||||
|
||||
echo '</thead>';
|
||||
|
||||
echo '<tbody>';
|
||||
|
||||
/* translators: %s: Number of calls to a PHP function */
|
||||
$call_text = _n_noop( '%s call', '%s calls', 'query-monitor' );
|
||||
|
||||
foreach ( $data->dupes as $sql => $queries ) {
|
||||
|
||||
// This should probably happen in the collector's processor
|
||||
$type = QM_Util::get_query_type( $sql );
|
||||
$sql_out = self::format_sql( $sql );
|
||||
$time = $data->dupe_times[ $sql ];
|
||||
|
||||
if ( 'SELECT' !== $type ) {
|
||||
$sql_out = "<span class='qm-nonselectsql'>{$sql_out}</span>";
|
||||
}
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td class="qm-row-sql qm-ltr qm-wrap">';
|
||||
echo $sql_out; // WPCS: XSS ok;
|
||||
echo '</td>';
|
||||
echo '<td class="qm-num">';
|
||||
echo esc_html( number_format_i18n( count( $queries ), 0 ) );
|
||||
echo '</td>';
|
||||
echo '<td class="qm-num">';
|
||||
echo esc_html( number_format_i18n( $time, 4 ) );
|
||||
echo '</td>';
|
||||
echo '<td class="qm-row-caller qm-nowrap qm-ltr">';
|
||||
foreach ( $data->dupe_callers[ $sql ] as $caller => $calls ) {
|
||||
echo self::build_filter_trigger( 'db_queries', 'caller', $caller, '<code>' . esc_html( $caller ) . '</code>' ); // WPCS: XSS ok;
|
||||
printf(
|
||||
'<br><span class="qm-info qm-supplemental">%s</span><br>',
|
||||
esc_html( sprintf(
|
||||
translate_nooped_plural( $call_text, $calls, 'query-monitor' ),
|
||||
number_format_i18n( $calls )
|
||||
) )
|
||||
);
|
||||
}
|
||||
echo '</td>';
|
||||
if ( isset( $data->dupe_components[ $sql ] ) ) {
|
||||
echo '<td class="qm-row-component qm-nowrap">';
|
||||
foreach ( $data->dupe_components[ $sql ] as $component => $calls ) {
|
||||
printf(
|
||||
'%s<br><span class="qm-info qm-supplemental">%s</span><br>',
|
||||
esc_html( $component ),
|
||||
esc_html( sprintf(
|
||||
translate_nooped_plural( $call_text, $calls, 'query-monitor' ),
|
||||
number_format_i18n( $calls )
|
||||
) )
|
||||
);
|
||||
}
|
||||
echo '</td>';
|
||||
}
|
||||
echo '<td class="qm-row-caller qm-nowrap qm-ltr">';
|
||||
foreach ( $data->dupe_sources[ $sql ] as $source => $calls ) {
|
||||
printf(
|
||||
'<code>%s</code><br><span class="qm-info qm-supplemental">%s</span><br>',
|
||||
esc_html( $source ),
|
||||
esc_html( sprintf(
|
||||
translate_nooped_plural( $call_text, $calls, 'query-monitor' ),
|
||||
number_format_i18n( $calls )
|
||||
) )
|
||||
);
|
||||
}
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
echo '</tbody>';
|
||||
|
||||
$this->after_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function admin_menu( array $menu ) {
|
||||
/** @var QM_Collector_DB_Dupes|null $dbq */
|
||||
$dbq = QM_Collectors::get( 'db_dupes' );
|
||||
|
||||
if ( $dbq ) {
|
||||
/** @var QM_Data_DB_Queries $dbq_data */
|
||||
$dbq_data = $dbq->get_data();
|
||||
if ( ! empty( $dbq_data->dupes ) ) {
|
||||
$count = 0;
|
||||
|
||||
foreach ( $dbq_data->dupes as $dupe ) {
|
||||
$count += count( $dupe );
|
||||
}
|
||||
|
||||
$menu[ $this->collector->id() ] = $this->menu( array(
|
||||
'title' => esc_html( sprintf(
|
||||
/* translators: %s: Number of duplicate database queries */
|
||||
__( 'Duplicate Queries (%s)', 'query-monitor' ),
|
||||
number_format_i18n( $count )
|
||||
) ),
|
||||
) );
|
||||
}
|
||||
}
|
||||
return $menu;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function panel_menu( array $menu ) {
|
||||
$id = $this->collector->id();
|
||||
if ( isset( $menu[ $id ] ) ) {
|
||||
$menu['qm-db_queries']['children'][] = $menu[ $id ];
|
||||
unset( $menu[ $id ] );
|
||||
}
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_db_dupes( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'db_dupes' );
|
||||
if ( $collector ) {
|
||||
$output['db_dupes'] = new QM_Output_Html_DB_Dupes( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_db_dupes', 45, 2 );
|
628
wp-content/plugins/query-monitor/output/html/db_queries.php
Normal file
628
wp-content/plugins/query-monitor/output/html/db_queries.php
Normal file
@ -0,0 +1,628 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Database query output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_DB_Queries extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_DB_Queries Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $query_row = 0;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 20 );
|
||||
add_filter( 'qm/output/panel_menus', array( $this, 'panel_menu' ), 20 );
|
||||
add_filter( 'qm/output/title', array( $this, 'admin_title' ), 20 );
|
||||
add_filter( 'qm/output/menu_class', array( $this, 'admin_class' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Database Queries', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_DB_Queries $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->wpdb ) ) {
|
||||
$this->output_empty_queries();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! empty( $data->errors ) ) {
|
||||
$this->output_error_queries( $data->errors );
|
||||
}
|
||||
|
||||
if ( ! empty( $data->expensive ) ) {
|
||||
$this->output_expensive_queries( $data->expensive );
|
||||
}
|
||||
|
||||
$this->output_queries( $data->wpdb, $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function output_empty_queries() {
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
if ( ! SAVEQUERIES ) {
|
||||
$notice = sprintf(
|
||||
/* translators: 1: Name of PHP constant, 2: Value of PHP constant */
|
||||
esc_html__( 'No database queries were logged because the %1$s constant is set to %2$s.', 'query-monitor' ),
|
||||
'<code>SAVEQUERIES</code>',
|
||||
'<code>false</code>'
|
||||
);
|
||||
} else {
|
||||
$notice = __( 'No database queries were logged.', 'query-monitor' );
|
||||
}
|
||||
|
||||
echo $this->build_notice( $notice ); // WPCS: XSS ok.
|
||||
$this->after_non_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, mixed> $errors
|
||||
* @return void
|
||||
*/
|
||||
protected function output_error_queries( array $errors ) {
|
||||
$this->before_tabular_output( 'qm-query-errors', __( 'Database Errors', 'query-monitor' ) );
|
||||
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col">' . esc_html__( 'Query', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Caller', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Component', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Error Message', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Error Code', 'query-monitor' ) . '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
echo '<tbody>';
|
||||
|
||||
foreach ( $errors as $row ) {
|
||||
$this->output_query_row( $row, array( 'sql', 'caller', 'component', 'errno', 'result' ) );
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
|
||||
$this->after_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, mixed> $expensive
|
||||
* @return void
|
||||
*/
|
||||
protected function output_expensive_queries( array $expensive ) {
|
||||
$dp = strlen( substr( strrchr( (string) QM_DB_EXPENSIVE, '.' ) ?: '.0', 1 ) );
|
||||
|
||||
$panel_name = sprintf(
|
||||
/* translators: %s: Database query time in seconds */
|
||||
esc_html__( 'Slow Database Queries (above %ss)', 'query-monitor' ),
|
||||
'<span class="qm-warn">' . esc_html( number_format_i18n( QM_DB_EXPENSIVE, $dp ) ) . '</span>'
|
||||
);
|
||||
$this->before_tabular_output( 'qm-query-expensive', $panel_name );
|
||||
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col">' . esc_html__( 'Query', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Caller', 'query-monitor' ) . '</th>';
|
||||
|
||||
if ( isset( $expensive[0]['component'] ) ) {
|
||||
echo '<th scope="col">' . esc_html__( 'Component', 'query-monitor' ) . '</th>';
|
||||
}
|
||||
|
||||
if ( isset( $expensive[0]['result'] ) ) {
|
||||
echo '<th scope="col" class="qm-num">' . esc_html__( 'Rows', 'query-monitor' ) . '</th>';
|
||||
}
|
||||
|
||||
echo '<th scope="col" class="qm-num">' . esc_html__( 'Time', 'query-monitor' ) . '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
echo '<tbody>';
|
||||
|
||||
foreach ( $expensive as $row ) {
|
||||
$this->output_query_row( $row, array( 'sql', 'caller', 'component', 'result', 'time' ) );
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
|
||||
$this->after_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stdClass $db
|
||||
* @param QM_Data_DB_Queries $data
|
||||
* @return void
|
||||
*/
|
||||
protected function output_queries( stdClass $db, QM_Data_DB_Queries $data ) {
|
||||
$this->query_row = 0;
|
||||
$span = 4;
|
||||
|
||||
if ( $db->has_result ) {
|
||||
$span++;
|
||||
}
|
||||
if ( $db->has_trace ) {
|
||||
$span++;
|
||||
}
|
||||
|
||||
if ( ! empty( $db->rows ) ) {
|
||||
$this->before_tabular_output();
|
||||
|
||||
echo '<thead>';
|
||||
|
||||
/**
|
||||
* Filter whether to show the QM extended query information prompt.
|
||||
*
|
||||
* By default QM shows a prompt to install the QM db.php drop-in,
|
||||
* this filter allows a dev to choose not to show the prompt.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param bool $show_prompt Whether to show the prompt.
|
||||
*/
|
||||
if ( apply_filters( 'qm/show_extended_query_prompt', true ) && ! $db->has_trace ) {
|
||||
echo '<tr>';
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<th colspan="' . intval( $span ) . '" class="qm-warn">' . QueryMonitor::icon( 'warning' );
|
||||
if ( file_exists( WP_CONTENT_DIR . '/db.php' ) ) {
|
||||
/* translators: %s: File name */
|
||||
$message = __( 'Extended query information such as the component and affected rows is not available. A conflicting %s file is present.', 'query-monitor' );
|
||||
} elseif ( defined( 'QM_DB_SYMLINK' ) && ! QM_DB_SYMLINK ) {
|
||||
/* translators: 1: File name, 2: Configuration constant name */
|
||||
$message = __( 'Extended query information such as the component and affected rows is not available. Query Monitor was prevented from symlinking its %1$s file into place by the %2$s constant.', 'query-monitor' );
|
||||
} else {
|
||||
/* translators: %s: File name */
|
||||
$message = __( 'Extended query information such as the component and affected rows is not available. Query Monitor was unable to symlink its %s file into place.', 'query-monitor' );
|
||||
}
|
||||
printf(
|
||||
esc_html( $message ),
|
||||
'<code>db.php</code>',
|
||||
'<code>QM_DB_SYMLINK</code>'
|
||||
);
|
||||
|
||||
printf(
|
||||
' <a href="%s" target="_blank" class="qm-external-link">See this wiki page for more information.</a>',
|
||||
'https://github.com/johnbillion/query-monitor/wiki/db.php-Symlink'
|
||||
);
|
||||
echo '</th>';
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
$types = array_keys( $db->types );
|
||||
$prepend = array();
|
||||
$callers = array_column( $data->times, 'caller' );
|
||||
|
||||
sort( $types );
|
||||
usort( $callers, 'strcasecmp' );
|
||||
|
||||
if ( count( $types ) > 1 ) {
|
||||
$prepend['non-select'] = __( 'Non-SELECT', 'query-monitor' );
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'prepend' => $prepend,
|
||||
);
|
||||
|
||||
echo '<tr>';
|
||||
echo '<th scope="col" class="qm-sorted-asc qm-sortable-column" role="columnheader" aria-sort="ascending">';
|
||||
echo $this->build_sorter( '#' ); // WPCS: XSS ok;
|
||||
echo '</th>';
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
echo $this->build_filter( 'type', $types, __( 'Query', 'query-monitor' ), $args ); // WPCS: XSS ok;
|
||||
echo '</th>';
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
|
||||
$prepend = array();
|
||||
|
||||
if ( $db->has_main_query ) {
|
||||
$prepend['qm-main-query'] = __( 'Main Query', 'query-monitor' );
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'prepend' => $prepend,
|
||||
);
|
||||
echo $this->build_filter( 'caller', $callers, __( 'Caller', 'query-monitor' ), $args ); // WPCS: XSS ok.
|
||||
echo '</th>';
|
||||
|
||||
if ( $db->has_trace ) {
|
||||
$components = array_column( $data->component_times, 'component' );
|
||||
|
||||
usort( $components, 'strcasecmp' );
|
||||
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
echo $this->build_filter( 'component', $components, __( 'Component', 'query-monitor' ) ); // WPCS: XSS ok.
|
||||
echo '</th>';
|
||||
}
|
||||
|
||||
if ( $db->has_result ) {
|
||||
if ( empty( $data->errors ) ) {
|
||||
$class = 'qm-num';
|
||||
} else {
|
||||
$class = '';
|
||||
}
|
||||
echo '<th scope="col" class="' . esc_attr( $class ) . ' qm-sortable-column" role="columnheader">';
|
||||
echo $this->build_sorter( __( 'Rows', 'query-monitor' ) ); // WPCS: XSS ok.
|
||||
echo '</th>';
|
||||
}
|
||||
|
||||
echo '<th scope="col" class="qm-num qm-sortable-column" role="columnheader">';
|
||||
echo $this->build_sorter( __( 'Time', 'query-monitor' ) ); // WPCS: XSS ok.
|
||||
echo '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
|
||||
echo '<tbody>';
|
||||
|
||||
foreach ( $db->rows as $row ) {
|
||||
$this->output_query_row( $row, array( 'row', 'sql', 'caller', 'component', 'result', 'time' ) );
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
echo '<tfoot>';
|
||||
|
||||
$total_stime = number_format_i18n( $db->total_time, 4 );
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td colspan="' . intval( $span - 1 ) . '">';
|
||||
printf(
|
||||
/* translators: %s: Number of database queries */
|
||||
esc_html( _nx( 'Total: %s', 'Total: %s', $db->total_qs, 'Query count', 'query-monitor' ) ),
|
||||
'<span class="qm-items-number">' . esc_html( number_format_i18n( $db->total_qs ) ) . '</span>'
|
||||
);
|
||||
echo '</td>';
|
||||
echo '<td class="qm-num qm-items-time">' . esc_html( $total_stime ) . '</td>';
|
||||
echo '</tr>';
|
||||
echo '</tfoot>';
|
||||
|
||||
$this->after_tabular_output();
|
||||
} else {
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
$notice = __( 'No queries! Nice work.', 'query-monitor' );
|
||||
echo $this->build_notice( $notice ); // WPCS: XSS ok.
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $row
|
||||
* @param array<int, string> $cols
|
||||
* @return void
|
||||
*/
|
||||
protected function output_query_row( array $row, array $cols ) {
|
||||
|
||||
$cols = array_flip( $cols );
|
||||
|
||||
if ( ! isset( $row['component'] ) ) {
|
||||
unset( $cols['component'] );
|
||||
}
|
||||
if ( ! isset( $row['result'] ) ) {
|
||||
unset( $cols['result'], $cols['errno'] );
|
||||
}
|
||||
|
||||
$stime = number_format_i18n( $row['ltime'], 4 );
|
||||
$sql = $row['sql'];
|
||||
|
||||
if ( 'Unknown' === $row['type'] ) {
|
||||
$sql = "<code>{$sql}</code>";
|
||||
} else {
|
||||
$sql = self::format_sql( $row['sql'] );
|
||||
}
|
||||
|
||||
if ( 'SELECT' !== $row['type'] ) {
|
||||
$sql = "<span class='qm-nonselectsql'>{$sql}</span>";
|
||||
}
|
||||
|
||||
if ( isset( $row['trace'] ) ) {
|
||||
|
||||
$caller = $row['trace']->get_caller();
|
||||
$caller_name = self::output_filename( $row['caller'], $caller['calling_file'], $caller['calling_line'] );
|
||||
$stack = array();
|
||||
$filtered_trace = $row['trace']->get_filtered_trace();
|
||||
array_shift( $filtered_trace );
|
||||
|
||||
foreach ( $filtered_trace as $frame ) {
|
||||
$stack[] = self::output_filename( $frame['display'], $frame['calling_file'], $frame['calling_line'] );
|
||||
}
|
||||
} else {
|
||||
|
||||
if ( ! empty( $row['caller'] ) ) {
|
||||
$caller_name = '<code>' . esc_html( $row['caller'] ) . '</code>';
|
||||
} else {
|
||||
$caller_name = '<code>' . esc_html__( 'Unknown', 'query-monitor' ) . '</code>';
|
||||
}
|
||||
|
||||
$stack = $row['stack'];
|
||||
array_shift( $stack );
|
||||
$stack = array_map( function( $frame ) {
|
||||
return '<code>' . esc_html( $frame ) . '</code>';
|
||||
}, $stack );
|
||||
|
||||
}
|
||||
|
||||
$row_attr = array();
|
||||
|
||||
if ( $row['result'] instanceof WP_Error ) {
|
||||
$row_attr['class'] = 'qm-warn';
|
||||
}
|
||||
if ( isset( $cols['sql'] ) ) {
|
||||
$row_attr['data-qm-type'] = $row['type'];
|
||||
if ( 'SELECT' !== $row['type'] ) {
|
||||
$row_attr['data-qm-type'] .= ' non-select';
|
||||
}
|
||||
}
|
||||
if ( isset( $cols['component'] ) && $row['component'] ) {
|
||||
$row_attr['data-qm-component'] = $row['component']->name;
|
||||
|
||||
if ( 'core' !== $row['component']->context ) {
|
||||
$row_attr['data-qm-component'] .= ' non-core';
|
||||
}
|
||||
}
|
||||
if ( isset( $cols['caller'] ) && ! empty( $row['caller_name'] ) ) {
|
||||
$row_attr['data-qm-caller'] = $row['caller_name'];
|
||||
|
||||
if ( $row['is_main_query'] ) {
|
||||
$row_attr['data-qm-caller'] .= ' qm-main-query';
|
||||
}
|
||||
}
|
||||
if ( isset( $cols['time'] ) ) {
|
||||
$row_attr['data-qm-time'] = $row['ltime'];
|
||||
}
|
||||
|
||||
$attr = '';
|
||||
|
||||
foreach ( $row_attr as $a => $v ) {
|
||||
$attr .= ' ' . $a . '="' . esc_attr( $v ) . '"';
|
||||
}
|
||||
|
||||
echo "<tr{$attr}>"; // WPCS: XSS ok.
|
||||
|
||||
if ( isset( $cols['row'] ) ) {
|
||||
echo '<th scope="row" class="qm-row-num qm-num">' . intval( ++$this->query_row ) . '</th>';
|
||||
}
|
||||
|
||||
if ( isset( $cols['sql'] ) ) {
|
||||
printf( // WPCS: XSS ok.
|
||||
'<td class="qm-row-sql qm-ltr qm-wrap">%s</td>',
|
||||
$sql
|
||||
);
|
||||
}
|
||||
|
||||
if ( isset( $cols['caller'] ) ) {
|
||||
echo '<td class="qm-row-caller qm-ltr qm-has-toggle qm-nowrap">';
|
||||
|
||||
if ( ! empty( $stack ) ) {
|
||||
echo self::build_toggler(); // WPCS: XSS ok;
|
||||
}
|
||||
|
||||
echo '<ol>';
|
||||
echo "<li>{$caller_name}</li>"; // WPCS: XSS ok.
|
||||
|
||||
if ( ! empty( $stack ) ) {
|
||||
echo '<div class="qm-toggled"><li>' . implode( '</li><li>', $stack ) . '</li></div>'; // WPCS: XSS ok.
|
||||
}
|
||||
|
||||
echo '</ol>';
|
||||
if ( $row['is_main_query'] ) {
|
||||
printf(
|
||||
'<p>%s</p>',
|
||||
esc_html__( 'Main Query', 'query-monitor' )
|
||||
);
|
||||
}
|
||||
echo '</td>';
|
||||
}
|
||||
|
||||
if ( isset( $cols['stack'] ) ) {
|
||||
echo '<td class="qm-row-caller qm-row-stack qm-nowrap qm-ltr"><ol>';
|
||||
if ( ! empty( $stack ) ) {
|
||||
echo '<li>' . implode( '</li><li>', $stack ) . '</li>'; // WPCS: XSS ok.
|
||||
}
|
||||
echo "<li>{$caller_name}</li>"; // WPCS: XSS ok.
|
||||
echo '</ol></td>';
|
||||
}
|
||||
|
||||
if ( isset( $cols['component'] ) ) {
|
||||
if ( $row['component'] ) {
|
||||
echo "<td class='qm-row-component qm-nowrap'>" . esc_html( $row['component']->name ) . "</td>\n";
|
||||
} else {
|
||||
echo "<td class='qm-row-component qm-nowrap'>" . esc_html__( 'Unknown', 'query-monitor' ) . "</td>\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $cols['result'] ) ) {
|
||||
if ( $row['result'] instanceof WP_Error ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo "<td class='qm-row-result qm-row-error'>" . QueryMonitor::icon( 'warning' ) . esc_html( $row['result']->get_error_message() ) . "</td>\n";
|
||||
} else {
|
||||
echo "<td class='qm-row-result qm-num'>" . esc_html( $row['result'] ) . "</td>\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $cols['errno'] ) && ( $row['result'] instanceof WP_Error ) ) {
|
||||
echo "<td class='qm-row-result qm-row-error'>" . esc_html( $row['result']->get_error_code() ) . "</td>\n";
|
||||
}
|
||||
|
||||
if ( isset( $cols['time'] ) ) {
|
||||
$expensive = $this->collector->is_expensive( $row );
|
||||
$td_class = ( $expensive ) ? ' qm-warn' : '';
|
||||
|
||||
echo '<td class="qm-num qm-row-time' . esc_attr( $td_class ) . '" data-qm-sort-weight="' . esc_attr( $row['ltime'] ) . '">';
|
||||
|
||||
if ( $expensive ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo QueryMonitor::icon( 'warning' );
|
||||
}
|
||||
|
||||
echo esc_html( $stime );
|
||||
echo "</td>\n";
|
||||
}
|
||||
|
||||
echo '</tr>';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, string> $title
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function admin_title( array $title ) {
|
||||
/** @var QM_Data_DB_Queries $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( isset( $data->wpdb ) ) {
|
||||
$title[] = sprintf(
|
||||
/* translators: %s: A time in seconds with a decimal fraction. No space between value and unit symbol. */
|
||||
esc_html_x( '%ss', 'Time in seconds', 'query-monitor' ),
|
||||
number_format_i18n( $data->wpdb->total_time, 2 )
|
||||
);
|
||||
|
||||
/* translators: %s: Number of database queries. Note the space between value and unit symbol. */
|
||||
$text = _n( '%s Q', '%s Q', $data->wpdb->total_qs, 'query-monitor' );
|
||||
|
||||
// Avoid a potentially blank translation for the plural form.
|
||||
// @see https://meta.trac.wordpress.org/ticket/5377
|
||||
if ( '' === $text ) {
|
||||
$text = '%s Q';
|
||||
}
|
||||
|
||||
$title[] = preg_replace( '#\s?([^0-9,\.]+)#', '<small>$1</small>', sprintf(
|
||||
esc_html( $text ),
|
||||
number_format_i18n( $data->wpdb->total_qs )
|
||||
) );
|
||||
} elseif ( isset( $data->total_qs ) ) {
|
||||
/* translators: %s: Number of database queries. Note the space between value and unit symbol. */
|
||||
$text = _n( '%s Q', '%s Q', $data->total_qs, 'query-monitor' );
|
||||
|
||||
// Avoid a potentially blank translation for the plural form.
|
||||
// @see https://meta.trac.wordpress.org/ticket/5377
|
||||
if ( '' === $text ) {
|
||||
$text = '%s Q';
|
||||
}
|
||||
|
||||
$title[] = preg_replace( '#\s?([^0-9,\.]+)#', '<small>$1</small>', sprintf(
|
||||
esc_html( $text ),
|
||||
number_format_i18n( $data->total_qs )
|
||||
) );
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, string> $class
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function admin_class( array $class ) {
|
||||
|
||||
if ( $this->collector->get_errors() ) {
|
||||
$class[] = 'qm-error';
|
||||
}
|
||||
if ( $this->collector->get_expensive() ) {
|
||||
$class[] = 'qm-expensive';
|
||||
}
|
||||
return $class;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function admin_menu( array $menu ) {
|
||||
/** @var QM_Data_DB_Queries $data */
|
||||
$data = $this->collector->get_data();
|
||||
$errors = $this->collector->get_errors();
|
||||
$expensive = $this->collector->get_expensive();
|
||||
|
||||
$id = $this->collector->id();
|
||||
$menu[ $id ] = $this->menu( array(
|
||||
'title' => esc_html__( 'Database Queries', 'query-monitor' ),
|
||||
// 'href' => esc_attr( sprintf( '#%s', $this->collector->id() ) ),
|
||||
) );
|
||||
|
||||
if ( $errors ) {
|
||||
$id = $this->collector->id() . '-errors';
|
||||
$count = count( $errors );
|
||||
$menu[ $id ] = $this->menu( array(
|
||||
'id' => 'query-monitor-errors',
|
||||
'href' => '#qm-query-errors',
|
||||
'title' => esc_html( sprintf(
|
||||
/* translators: %s: Number of database errors */
|
||||
__( 'Database Errors (%s)', 'query-monitor' ),
|
||||
number_format_i18n( $count )
|
||||
) ),
|
||||
) );
|
||||
}
|
||||
|
||||
if ( $expensive ) {
|
||||
$id = $this->collector->id() . '-expensive';
|
||||
$count = count( $expensive );
|
||||
$menu[ $id ] = $this->menu( array(
|
||||
'id' => 'query-monitor-expensive',
|
||||
'href' => '#qm-query-expensive',
|
||||
'title' => esc_html( sprintf(
|
||||
/* translators: %s: Number of slow database queries */
|
||||
__( 'Slow Queries (%s)', 'query-monitor' ),
|
||||
number_format_i18n( $count )
|
||||
) ),
|
||||
) );
|
||||
}
|
||||
|
||||
return $menu;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function panel_menu( array $menu ) {
|
||||
foreach ( array( 'errors', 'expensive' ) as $sub ) {
|
||||
$id = $this->collector->id() . '-' . $sub;
|
||||
if ( isset( $menu[ $id ] ) ) {
|
||||
$menu['qm-db_queries']['children'][] = $menu[ $id ];
|
||||
unset( $menu[ $id ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_db_queries( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'db_queries' );
|
||||
if ( $collector ) {
|
||||
$output['db_queries'] = new QM_Output_Html_DB_Queries( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_db_queries', 20, 2 );
|
114
wp-content/plugins/query-monitor/output/html/debug_bar.php
Normal file
114
wp-content/plugins/query-monitor/output/html/debug_bar.php
Normal file
@ -0,0 +1,114 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* 'Debug Bar' output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Debug_Bar extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Debug_Bar Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
/** @var string */
|
||||
return $this->collector->get_panel()->title();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
$class = get_class( $this->collector->get_panel() );
|
||||
|
||||
if ( ! $class ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$target = sanitize_html_class( $class );
|
||||
|
||||
$this->before_debug_bar_output();
|
||||
|
||||
echo '<div id="debug-menu-target-' . esc_attr( $target ) . '" class="debug-menu-target qm-debug-bar-output">';
|
||||
|
||||
ob_start();
|
||||
$this->collector->render();
|
||||
$panel = (string) ob_get_clean();
|
||||
|
||||
$panel = str_replace( array(
|
||||
'<h4',
|
||||
'<h3',
|
||||
'<h2',
|
||||
'<h1',
|
||||
'</h4>',
|
||||
'</h3>',
|
||||
'</h2>',
|
||||
'</h1>',
|
||||
), array(
|
||||
'<h5',
|
||||
'<h4',
|
||||
'<h3',
|
||||
'<h2',
|
||||
'</h5>',
|
||||
'</h4>',
|
||||
'</h3>',
|
||||
'</h2>',
|
||||
), $panel );
|
||||
|
||||
echo $panel; // phpcs:ignore
|
||||
|
||||
echo '</div>';
|
||||
|
||||
$this->after_debug_bar_output();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_debug_bar( array $output, QM_Collectors $collectors ) {
|
||||
global $debug_bar;
|
||||
|
||||
if ( empty( $debug_bar ) ) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
foreach ( $debug_bar->panels as $panel ) {
|
||||
$class = get_class( $panel );
|
||||
|
||||
if ( ! $class ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$panel_id = strtolower( sanitize_html_class( $class ) );
|
||||
/** @var QM_Collector_Debug_Bar|null */
|
||||
$collector = QM_Collectors::get( "debug_bar_{$panel_id}" );
|
||||
|
||||
if ( $collector && $collector->is_visible() ) {
|
||||
$output[ "debug_bar_{$panel_id}" ] = new QM_Output_Html_Debug_Bar( $collector );
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_debug_bar', 200, 2 );
|
194
wp-content/plugins/query-monitor/output/html/doing_it_wrong.php
Normal file
194
wp-content/plugins/query-monitor/output/html/doing_it_wrong.php
Normal file
@ -0,0 +1,194 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Doing it Wrong output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Doing_It_Wrong extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Doing_It_Wrong Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 15 );
|
||||
add_filter( 'qm/output/menu_class', array( $this, 'admin_class' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Doing it Wrong', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function get_type_labels() {
|
||||
return array(
|
||||
/* translators: %s: Total number of Doing it Wrong occurrences */
|
||||
'total' => _x( 'Total: %s', 'Doing it Wrong', 'query-monitor' ),
|
||||
'plural' => __( 'Doing it Wrong occurrences', 'query-monitor' ),
|
||||
/* translators: %s: Total number of Doing it Wrong occurrences */
|
||||
'count' => _x( 'Doing it Wrong (%s)', 'Doing it Wrong', 'query-monitor' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_Doing_It_Wrong $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->actions ) ) {
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
$notice = __( 'No occurrences.', 'query-monitor' );
|
||||
echo $this->build_notice( $notice ); // WPCS: XSS ok.
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->before_tabular_output();
|
||||
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col">' . esc_html__( 'Message', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Caller', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Component', 'query-monitor' ) . '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
|
||||
echo '<tbody>';
|
||||
|
||||
foreach ( $data->actions as $row ) {
|
||||
$stack = array();
|
||||
|
||||
foreach ( $row['filtered_trace'] as $frame ) {
|
||||
$stack[] = self::output_filename( $frame['display'], $frame['calling_file'], $frame['calling_line'] );
|
||||
}
|
||||
|
||||
$caller = array_shift( $stack );
|
||||
|
||||
echo '<tr>';
|
||||
|
||||
printf( '<td>%s</td>', esc_html( wp_strip_all_tags( $row['message'] ) ) );
|
||||
|
||||
echo '<td class="qm-has-toggle qm-nowrap qm-ltr">';
|
||||
|
||||
if ( ! empty( $stack ) ) {
|
||||
echo self::build_toggler(); // WPCS: XSS ok;
|
||||
}
|
||||
|
||||
echo '<ol>';
|
||||
|
||||
echo "<li>{$caller}</li>"; // WPCS: XSS ok.
|
||||
|
||||
if ( ! empty( $stack ) ) {
|
||||
echo '<div class="qm-toggled"><li>' . implode( '</li><li>', $stack ) . '</li></div>'; // WPCS: XSS ok.
|
||||
}
|
||||
|
||||
echo '</ol></td>';
|
||||
|
||||
echo '<td class="qm-nowrap">' . esc_html( $row['component']->name ) . '</td>';
|
||||
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
|
||||
echo '<tfoot>';
|
||||
printf(
|
||||
'<tr><td colspan="3">%s</td></tr>',
|
||||
sprintf(
|
||||
/* translators: %s: Total number of Doing it Wrong occurrences */
|
||||
esc_html_x( 'Total: %s', 'Total Doing it Wrong occurrences', 'query-monitor' ),
|
||||
'<span class="qm-items-number">' . esc_html( number_format_i18n( count( $data->actions ) ) ) . '</span>'
|
||||
)
|
||||
);
|
||||
echo '</tfoot>';
|
||||
|
||||
$this->after_tabular_output();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, string> $class
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function admin_class( array $class ) {
|
||||
/** @var QM_Data_Doing_It_Wrong */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( ! empty( $data->actions ) ) {
|
||||
$class[] = 'qm-notice';
|
||||
}
|
||||
|
||||
return $class;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function admin_menu( array $menu ) {
|
||||
/** @var QM_Data_Doing_It_Wrong */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->actions ) ) {
|
||||
return $menu;
|
||||
}
|
||||
|
||||
$type_label = $this->get_type_labels();
|
||||
$label = sprintf(
|
||||
$type_label['count'],
|
||||
number_format_i18n( count( $data->actions ) )
|
||||
);
|
||||
|
||||
$args = array(
|
||||
'title' => esc_html( $label ),
|
||||
'id' => esc_attr( "query-monitor-{$this->collector->id}" ),
|
||||
'href' => esc_attr( '#' . $this->collector->id() ),
|
||||
);
|
||||
|
||||
if ( ! empty( $data->actions ) ) {
|
||||
$args['meta']['classname'] = 'qm-notice';
|
||||
}
|
||||
|
||||
$id = $this->collector->id();
|
||||
$menu[ $id ] = $this->menu( $args );
|
||||
|
||||
return $menu;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_doing_it_wrong( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'doing_it_wrong' );
|
||||
if ( $collector ) {
|
||||
$output['doing_it_wrong'] = new QM_Output_Html_Doing_It_Wrong( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_doing_it_wrong', 110, 2 );
|
315
wp-content/plugins/query-monitor/output/html/environment.php
Normal file
315
wp-content/plugins/query-monitor/output/html/environment.php
Normal file
@ -0,0 +1,315 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Environment data output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Environment extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Environment Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 110 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Environment', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_Environment $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3>PHP</h3>';
|
||||
|
||||
echo '<table>';
|
||||
echo '<tbody>';
|
||||
|
||||
$append = '';
|
||||
$class = '';
|
||||
$php_warning = $data->php['old'];
|
||||
|
||||
if ( $php_warning ) {
|
||||
$append .= sprintf(
|
||||
' <span class="qm-info">(<a href="%s" target="_blank" class="qm-external-link">%s</a>)</span>',
|
||||
'https://wordpress.org/support/update-php/',
|
||||
esc_html__( 'Help', 'query-monitor' )
|
||||
);
|
||||
$class = 'qm-warn';
|
||||
}
|
||||
|
||||
echo '<tr class="' . esc_attr( $class ) . '">';
|
||||
echo '<th scope="row">' . esc_html__( 'Version', 'query-monitor' ) . '</th>';
|
||||
echo '<td>';
|
||||
|
||||
if ( $php_warning ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo QueryMonitor::icon( 'warning' );
|
||||
}
|
||||
|
||||
echo esc_html( $data->php['version'] ?: esc_html__( 'Unknown', 'query-monitor' ) );
|
||||
echo $append; // WPCS: XSS ok.
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
|
||||
echo '<tr>';
|
||||
echo '<th scope="row">SAPI</th>';
|
||||
echo '<td>' . esc_html( $data->php['sapi'] ?: esc_html__( 'Unknown', 'query-monitor' ) ) . '</td>';
|
||||
echo '</tr>';
|
||||
|
||||
echo '<tr>';
|
||||
echo '<th scope="row">' . esc_html__( 'User', 'query-monitor' ) . '</th>';
|
||||
if ( ! empty( $data->php['user'] ) ) {
|
||||
echo '<td>' . esc_html( $data->php['user'] ) . '</td>';
|
||||
} else {
|
||||
echo '<td><em>' . esc_html__( 'Unknown', 'query-monitor' ) . '</em></td>';
|
||||
}
|
||||
echo '</tr>';
|
||||
|
||||
foreach ( $data->php['variables'] as $key => $val ) {
|
||||
echo '<tr>';
|
||||
echo '<th scope="row">' . esc_html( $key ) . '</th>';
|
||||
echo '<td>';
|
||||
echo esc_html( $val );
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
$out = array();
|
||||
|
||||
foreach ( $data->php['error_levels'] as $level => $reported ) {
|
||||
if ( $reported ) {
|
||||
$out[] = esc_html( $level ) . ' ✓';
|
||||
} else {
|
||||
$out[] = '<span class="qm-false">' . esc_html( $level ) . '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
$error_levels = implode( '</li><li>', $out );
|
||||
|
||||
echo '<tr>';
|
||||
echo '<th scope="row">' . esc_html__( 'Error Reporting', 'query-monitor' ) . '</th>';
|
||||
echo '<td class="qm-has-toggle qm-ltr">';
|
||||
|
||||
echo esc_html( (string) $data->php['error_reporting'] );
|
||||
echo self::build_toggler(); // WPCS: XSS ok;
|
||||
|
||||
echo '<div class="qm-toggled">';
|
||||
echo "<ul class='qm-supplemental'><li>{$error_levels}</li></ul>"; // WPCS: XSS ok.
|
||||
echo '</div>';
|
||||
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
|
||||
if ( ! empty( $data->php['extensions'] ) ) {
|
||||
echo '<tr>';
|
||||
echo '<th scope="row">' . esc_html__( 'Extensions', 'query-monitor' ) . '</th>';
|
||||
echo '<td class="qm-has-inner qm-has-toggle qm-ltr">';
|
||||
|
||||
printf( // WPCS: XSS ok.
|
||||
'<div class="qm-inner-toggle">%1$s %2$s</div>',
|
||||
esc_html( number_format_i18n( count( $data->php['extensions'] ) ) ),
|
||||
self::build_toggler()
|
||||
);
|
||||
|
||||
echo '<div class="qm-toggled">';
|
||||
self::output_inner( $data->php['extensions'] );
|
||||
echo '</div>';
|
||||
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
echo '</table>';
|
||||
|
||||
echo '</section>';
|
||||
|
||||
if ( isset( $data->db ) ) {
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'Database', 'query-monitor' ) . '</h3>';
|
||||
|
||||
echo '<table>';
|
||||
echo '<tbody>';
|
||||
|
||||
$info = array(
|
||||
'server-version' => __( 'Server Version', 'query-monitor' ),
|
||||
'extension' => __( 'Extension', 'query-monitor' ),
|
||||
'client-version' => __( 'Client Version', 'query-monitor' ),
|
||||
'user' => __( 'User', 'query-monitor' ),
|
||||
'host' => __( 'Host', 'query-monitor' ),
|
||||
'database' => __( 'Database', 'query-monitor' ),
|
||||
);
|
||||
|
||||
foreach ( $info as $field => $label ) {
|
||||
|
||||
echo '<tr>';
|
||||
echo '<th scope="row">' . esc_html( $label ) . '</th>';
|
||||
|
||||
if ( ! isset( $data->db['info'][ $field ] ) ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<td><span class="qm-warn">' . QueryMonitor::icon( 'warning' ) . esc_html__( 'Unknown', 'query-monitor' ) . '</span></td>';
|
||||
} else {
|
||||
echo '<td>' . esc_html( $data->db['info'][ $field ] ) . '</td>';
|
||||
}
|
||||
|
||||
echo '</tr>';
|
||||
|
||||
}
|
||||
|
||||
foreach ( $data->db['variables'] as $setting ) {
|
||||
|
||||
// phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
$key = (string) $setting->Variable_name;
|
||||
// phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
$val = (string) $setting->Value;
|
||||
|
||||
$append = '';
|
||||
|
||||
if ( is_numeric( $val ) && ( $val >= ( 1024 * 1024 ) ) ) {
|
||||
$append .= sprintf(
|
||||
' <span class="qm-info">(~%s)</span>',
|
||||
esc_html( (string) size_format( $val ) )
|
||||
);
|
||||
}
|
||||
|
||||
echo '<tr>';
|
||||
|
||||
echo '<th scope="row">' . esc_html( $key ) . '</th>';
|
||||
echo '<td>';
|
||||
echo esc_html( $val );
|
||||
echo $append; // WPCS: XSS ok.
|
||||
echo '</td>';
|
||||
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
echo '</table>';
|
||||
|
||||
echo '</section>';
|
||||
}
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3>WordPress</h3>';
|
||||
|
||||
echo '<table>';
|
||||
echo '<tbody>';
|
||||
|
||||
echo '<tr>';
|
||||
echo '<th scope="row">' . esc_html__( 'Version', 'query-monitor' ) . '</th>';
|
||||
echo '<td>' . esc_html( $data->wp['version'] ) . '</td>';
|
||||
echo '</tr>';
|
||||
|
||||
if ( isset( $data->wp['environment_type'] ) ) {
|
||||
echo '<tr>';
|
||||
echo '<th scope="row">';
|
||||
esc_html_e( 'Environment Type', 'query-monitor' );
|
||||
printf(
|
||||
' <span class="qm-info">(<a href="%s" target="_blank" class="qm-external-link">%s</a>)</span>',
|
||||
'https://make.wordpress.org/core/2020/07/24/new-wp_get_environment_type-function-in-wordpress-5-5/',
|
||||
esc_html__( 'Help', 'query-monitor' )
|
||||
);
|
||||
echo '</th>';
|
||||
echo '<td>' . esc_html( $data->wp['environment_type'] ) . '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
if ( isset( $data->wp['development_mode'] ) ) {
|
||||
echo '<tr>';
|
||||
echo '<th scope="row">';
|
||||
esc_html_e( 'Development Mode', 'query-monitor' );
|
||||
printf(
|
||||
' <span class="qm-info">(<a href="%s" target="_blank" class="qm-external-link">%s</a>)</span>',
|
||||
'https://core.trac.wordpress.org/changeset/56042',
|
||||
esc_html__( 'Help', 'query-monitor' )
|
||||
);
|
||||
echo '</th>';
|
||||
echo '<td>' . esc_html( $data->wp['development_mode'] ) . '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
foreach ( $data->wp['constants'] as $key => $val ) {
|
||||
|
||||
echo '<tr>';
|
||||
echo '<th scope="row">' . esc_html( $key ) . '</th>';
|
||||
echo '<td>' . esc_html( $val ) . '</td>';
|
||||
echo '</tr>';
|
||||
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
echo '</table>';
|
||||
|
||||
echo '</section>';
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'Server', 'query-monitor' ) . '</h3>';
|
||||
|
||||
$server = array(
|
||||
'name' => __( 'Software', 'query-monitor' ),
|
||||
'version' => __( 'Version', 'query-monitor' ),
|
||||
'address' => __( 'IP Address', 'query-monitor' ),
|
||||
'host' => __( 'Host', 'query-monitor' ),
|
||||
/* translators: OS stands for Operating System */
|
||||
'OS' => __( 'OS', 'query-monitor' ),
|
||||
'arch' => __( 'Architecture', 'query-monitor' ),
|
||||
);
|
||||
|
||||
echo '<table>';
|
||||
echo '<tbody>';
|
||||
|
||||
foreach ( $server as $field => $label ) {
|
||||
echo '<tr>';
|
||||
echo '<th scope="row">' . esc_html( $label ) . '</th>';
|
||||
if ( ! empty( $data->server[ $field ] ) ) {
|
||||
echo '<td>' . esc_html( $data->server[ $field ] ) . '</td>';
|
||||
} else {
|
||||
echo '<td><em>' . esc_html__( 'Unknown', 'query-monitor' ) . '</em></td>';
|
||||
}
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
echo '</table>';
|
||||
echo '</section>';
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_environment( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'environment' );
|
||||
if ( $collector ) {
|
||||
$output['environment'] = new QM_Output_Html_Environment( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_environment', 120, 2 );
|
146
wp-content/plugins/query-monitor/output/html/headers.php
Normal file
146
wp-content/plugins/query-monitor/output/html/headers.php
Normal file
@ -0,0 +1,146 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Request and response headers output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Headers extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Raw_Request Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/panel_menus', array( $this, 'panel_menu' ), 20 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Collector name.
|
||||
*
|
||||
* This is unused.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Request Data', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
$this->output_request();
|
||||
$this->output_response();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output_request() {
|
||||
/** @var QM_Data_Raw_Request $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
$this->before_tabular_output();
|
||||
|
||||
$this->output_header_table( $data->request['headers'], __( 'Request Header Name', 'query-monitor' ) );
|
||||
|
||||
$this->after_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output_response() {
|
||||
/** @var QM_Data_Raw_Request $data */
|
||||
$data = $this->collector->get_data();
|
||||
$id = sprintf( 'qm-%s-response', $this->collector->id );
|
||||
|
||||
$this->before_tabular_output( $id );
|
||||
|
||||
$this->output_header_table( $data->response['headers'], __( 'Response Header Name', 'query-monitor' ) );
|
||||
|
||||
$this->after_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $headers
|
||||
* @param string $title
|
||||
* @return void
|
||||
*/
|
||||
protected function output_header_table( array $headers, $title ) {
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th>';
|
||||
echo esc_html( $title );
|
||||
echo '</th><th>';
|
||||
esc_html_e( 'Value', 'query-monitor' );
|
||||
echo '</th></tr>';
|
||||
echo '<tbody>';
|
||||
|
||||
foreach ( $headers as $name => $value ) {
|
||||
echo '<tr>';
|
||||
$formatted = str_replace( ' ', '-', ucwords( strtolower( str_replace( array( '-', '_' ), ' ', $name ) ) ) );
|
||||
printf( '<th scope="row"><code>%s</code></th>', esc_html( $formatted ) );
|
||||
printf( '<td><pre class="qm-pre-wrap"><code>%s</code></pre></td>', esc_html( $value ) );
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
|
||||
echo '<tfoot>';
|
||||
echo '<tr>';
|
||||
echo '<td colspan="2">';
|
||||
esc_html_e( 'Note that header names are not case-sensitive.', 'query-monitor' );
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
echo '</tfoot>';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function panel_menu( array $menu ) {
|
||||
if ( ! isset( $menu['qm-request'] ) ) {
|
||||
return $menu;
|
||||
}
|
||||
|
||||
$ids = array(
|
||||
$this->collector->id() => __( 'Request Headers', 'query-monitor' ),
|
||||
$this->collector->id() . '-response' => __( 'Response Headers', 'query-monitor' ),
|
||||
);
|
||||
foreach ( $ids as $id => $title ) {
|
||||
$menu['qm-request']['children'][] = array(
|
||||
'id' => $id,
|
||||
'href' => '#' . $id,
|
||||
'title' => esc_html( $title ),
|
||||
);
|
||||
}
|
||||
|
||||
return $menu;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_headers( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'raw_request' );
|
||||
if ( $collector ) {
|
||||
$output['raw_request'] = new QM_Output_Html_Headers( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_headers', 100, 2 );
|
255
wp-content/plugins/query-monitor/output/html/hooks.php
Normal file
255
wp-content/plugins/query-monitor/output/html/hooks.php
Normal file
@ -0,0 +1,255 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Hooks and actions output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Hooks extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Hooks Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 80 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
/** @var QM_Data_Hooks */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
$name = __( 'Hooks & Actions', 'query-monitor' );
|
||||
|
||||
if ( $data->all_hooks ) {
|
||||
$name = __( 'Hooks, Actions, & Filters', 'query-monitor' );
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_Hooks */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->hooks ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->before_tabular_output();
|
||||
|
||||
$callback_label = __( 'Action', 'query-monitor' );
|
||||
$th_type = '';
|
||||
|
||||
if ( $data->all_hooks ) {
|
||||
$callback_label = __( 'Callback', 'query-monitor' );
|
||||
$th_type = '<th scope="col" class="qm-filterable-column">' . $this->build_filter( 'type', array(
|
||||
'action' => __( 'Action', 'query-monitor' ),
|
||||
'filter' => __( 'Filter', 'query-monitor' ),
|
||||
), __( 'Type', 'query-monitor' ) ) . '</th>';
|
||||
}
|
||||
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
echo $this->build_filter( 'name', $data->parts, __( 'Hook', 'query-monitor' ) ); // WPCS: XSS ok.
|
||||
echo '</th>';
|
||||
echo $th_type; // WPCS: XSS ok.
|
||||
echo '<th scope="col">' . esc_html__( 'Priority', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html( $callback_label ) . '</th>';
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
echo $this->build_filter( 'component', $data->components, __( 'Component', 'query-monitor' ), array(
|
||||
'highlight' => 'subject',
|
||||
) ); // WPCS: XSS ok.
|
||||
echo '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
|
||||
echo '<tbody>';
|
||||
self::output_hook_table( $data->hooks, $data->all_hooks );
|
||||
echo '</tbody>';
|
||||
|
||||
$this->after_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, mixed[]> $hooks
|
||||
* @param bool $all_hooks
|
||||
* @return void
|
||||
*/
|
||||
public static function output_hook_table( array $hooks, bool $all_hooks ) {
|
||||
$core = __( 'WordPress Core', 'query-monitor' );
|
||||
|
||||
foreach ( $hooks as $hook ) {
|
||||
$row_attr = array();
|
||||
$row_attr['data-qm-name'] = implode( ' ', $hook['parts'] );
|
||||
$row_attr['data-qm-component'] = implode( ' ', $hook['components'] );
|
||||
$row_attr['data-qm-type'] = $hook['type'];
|
||||
|
||||
if ( ! empty( $row_attr['data-qm-component'] ) && $core !== $row_attr['data-qm-component'] ) {
|
||||
$row_attr['data-qm-component'] .= ' non-core';
|
||||
}
|
||||
|
||||
$attr = '';
|
||||
|
||||
if ( ! empty( $hook['actions'] ) ) {
|
||||
$rowspan = count( $hook['actions'] );
|
||||
} else {
|
||||
$rowspan = 1;
|
||||
}
|
||||
|
||||
foreach ( $row_attr as $a => $v ) {
|
||||
$attr .= ' ' . $a . '="' . esc_attr( $v ) . '"';
|
||||
}
|
||||
|
||||
if ( ! empty( $hook['actions'] ) ) {
|
||||
|
||||
$first = true;
|
||||
|
||||
foreach ( $hook['actions'] as $action ) {
|
||||
$component = '';
|
||||
$subject = '';
|
||||
|
||||
if ( isset( $action['callback']['component'] ) ) {
|
||||
$component = $action['callback']['component']->name;
|
||||
$subject = $component;
|
||||
}
|
||||
|
||||
if ( $core !== $component ) {
|
||||
$subject .= ' non-core';
|
||||
}
|
||||
|
||||
printf( // WPCS: XSS ok.
|
||||
'<tr data-qm-subject="%s" %s>',
|
||||
esc_attr( $subject ),
|
||||
$attr
|
||||
);
|
||||
|
||||
if ( $first ) {
|
||||
|
||||
echo '<th scope="row" rowspan="' . intval( $rowspan ) . '" class="qm-nowrap qm-ltr"><span class="qm-sticky">';
|
||||
echo '<code>' . esc_html( $hook['name'] ) . '</code>';
|
||||
if ( 'all' === $hook['name'] ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<br><span class="qm-warn">' . QueryMonitor::icon( 'warning' );
|
||||
printf(
|
||||
/* translators: %s: Action name */
|
||||
esc_html__( 'Warning: The %s action is extremely resource intensive. Try to avoid using it.', 'query-monitor' ),
|
||||
'<code>all</code>'
|
||||
);
|
||||
echo '</span>';
|
||||
}
|
||||
echo '</span></th>';
|
||||
|
||||
if ( $all_hooks ) {
|
||||
$type = ( 'action' === $hook['type'] ) ? __( 'Action', 'query-monitor' ) : __( 'Filter', 'query-monitor' );
|
||||
echo '<td rowspan="' . intval( $rowspan ) . '" class="qm-nowrap qm-ltr"><span class="qm-sticky">' . esc_html( $type ) . '</td>';
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $action['callback']['error'] ) ) {
|
||||
$class = ' qm-warn';
|
||||
} else {
|
||||
$class = '';
|
||||
}
|
||||
|
||||
echo '<td class="qm-num' . esc_attr( $class ) . '">';
|
||||
|
||||
echo esc_html( $action['priority'] );
|
||||
|
||||
if ( PHP_INT_MAX === $action['priority'] ) {
|
||||
echo ' <span class="qm-info">(PHP_INT_MAX)</span>';
|
||||
} elseif ( PHP_INT_MIN === $action['priority'] ) {
|
||||
echo ' <span class="qm-info">(PHP_INT_MIN)</span>';
|
||||
} elseif ( -PHP_INT_MAX === $action['priority'] ) {
|
||||
echo ' <span class="qm-info">(-PHP_INT_MAX)</span>';
|
||||
}
|
||||
|
||||
echo '</td>';
|
||||
|
||||
if ( isset( $action['callback']['file'] ) ) {
|
||||
if ( self::has_clickable_links() ) {
|
||||
echo '<td class="qm-nowrap qm-ltr' . esc_attr( $class ) . '">';
|
||||
echo self::output_filename( $action['callback']['name'], $action['callback']['file'], $action['callback']['line'] ); // WPCS: XSS ok.
|
||||
echo '</td>';
|
||||
} else {
|
||||
echo '<td class="qm-nowrap qm-ltr qm-has-toggle' . esc_attr( $class ) . '">';
|
||||
echo self::build_toggler(); // WPCS: XSS ok;
|
||||
echo '<ol>';
|
||||
echo '<li>';
|
||||
echo self::output_filename( $action['callback']['name'], $action['callback']['file'], $action['callback']['line'] ); // WPCS: XSS ok.
|
||||
echo '</li>';
|
||||
echo '</ol></td>';
|
||||
}
|
||||
} else {
|
||||
echo '<td class="qm-ltr qm-nowrap' . esc_attr( $class ) . '">';
|
||||
echo '<code>' . esc_html( $action['callback']['name'] ) . '</code>';
|
||||
|
||||
if ( isset( $action['callback']['error'] ) ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<br>' . QueryMonitor::icon( 'warning' );
|
||||
echo esc_html( sprintf(
|
||||
/* translators: %s: Error message text */
|
||||
__( 'Error: %s', 'query-monitor' ),
|
||||
$action['callback']['error']->get_error_message()
|
||||
) );
|
||||
}
|
||||
|
||||
echo '</td>';
|
||||
}
|
||||
|
||||
echo '<td class="qm-nowrap' . esc_attr( $class ) . '">';
|
||||
echo esc_html( $component );
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
$first = false;
|
||||
}
|
||||
} else {
|
||||
echo "<tr{$attr}>"; // WPCS: XSS ok.
|
||||
echo '<th scope="row" class="qm-ltr">';
|
||||
echo '<code>' . esc_html( $hook['name'] ) . '</code>';
|
||||
echo '</th>';
|
||||
echo '<td></td>';
|
||||
echo '<td></td>';
|
||||
echo '<td></td>';
|
||||
|
||||
if ( $all_hooks ) {
|
||||
echo '<td></td>';
|
||||
}
|
||||
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_hooks( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'hooks' );
|
||||
if ( $collector ) {
|
||||
$output['hooks'] = new QM_Output_Html_Hooks( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_hooks', 80, 2 );
|
391
wp-content/plugins/query-monitor/output/html/http.php
Normal file
391
wp-content/plugins/query-monitor/output/html/http.php
Normal file
@ -0,0 +1,391 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* HTTP API request output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_HTTP extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_HTTP Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 90 );
|
||||
add_filter( 'qm/output/menu_class', array( $this, 'admin_class' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'HTTP API Calls', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_HTTP $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( ! empty( $data->http ) ) {
|
||||
$statuses = array_keys( $data->types );
|
||||
$components = array_column( $data->component_times, 'component' );
|
||||
|
||||
usort( $statuses, 'strcasecmp' );
|
||||
usort( $components, 'strcasecmp' );
|
||||
|
||||
$status_output = array();
|
||||
$hosts = array_unique( array_column( $data->http, 'host' ) );
|
||||
sort( $hosts );
|
||||
|
||||
foreach ( $statuses as $status ) {
|
||||
if ( 'error' === $status ) {
|
||||
$status_output['error'] = __( 'Error', 'query-monitor' );
|
||||
} elseif ( 'non-blocking' === $status ) {
|
||||
/* translators: A non-blocking HTTP API request */
|
||||
$status_output['non-blocking'] = __( 'Non-blocking', 'query-monitor' );
|
||||
} else {
|
||||
$status_output[] = $status;
|
||||
}
|
||||
}
|
||||
|
||||
$this->before_tabular_output();
|
||||
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col">' . esc_html__( 'Method', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
echo $this->build_filter( 'host', $hosts, __( 'URL', 'query-monitor' ) ); // WPCS: XSS ok.
|
||||
echo '</th>';
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
echo $this->build_filter( 'type', $status_output, __( 'Status', 'query-monitor' ) ); // WPCS: XSS ok.
|
||||
echo '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Caller', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
echo $this->build_filter( 'component', $components, __( 'Component', 'query-monitor' ) ); // WPCS: XSS ok.
|
||||
echo '</th>';
|
||||
echo '<th scope="col" class="qm-num">' . esc_html__( 'Size', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col" class="qm-num">' . esc_html__( 'Timeout', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col" class="qm-num">' . esc_html__( 'Time', 'query-monitor' ) . '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
|
||||
echo '<tbody>';
|
||||
$i = 0;
|
||||
|
||||
foreach ( $data->http as $row ) {
|
||||
$ltime = $row['ltime'];
|
||||
$i++;
|
||||
$is_error = false;
|
||||
$row_attr = array();
|
||||
$css = '';
|
||||
|
||||
if ( $row['response'] instanceof WP_Error ) {
|
||||
$response = $row['response']->get_error_message();
|
||||
$is_error = true;
|
||||
} elseif ( ! $row['args']['blocking'] ) {
|
||||
/* translators: A non-blocking HTTP API request */
|
||||
$response = __( 'Non-blocking', 'query-monitor' );
|
||||
} else {
|
||||
$code = wp_remote_retrieve_response_code( $row['response'] );
|
||||
$msg = wp_remote_retrieve_response_message( $row['response'] );
|
||||
|
||||
if ( intval( $code ) >= 400 ) {
|
||||
$is_error = true;
|
||||
}
|
||||
|
||||
$response = $code . ' ' . $msg;
|
||||
|
||||
}
|
||||
|
||||
if ( $is_error ) {
|
||||
$css = 'qm-warn';
|
||||
}
|
||||
|
||||
$url = self::format_url( $row['url'] );
|
||||
$info = '';
|
||||
|
||||
$url = preg_replace( '|^http:|', '<span class="qm-warn">http</span>:', $url );
|
||||
|
||||
if ( 'https' === parse_url( $row['url'], PHP_URL_SCHEME ) ) {
|
||||
if ( empty( $row['args']['sslverify'] ) && ! $row['local'] ) {
|
||||
$info .= '<span class="qm-warn">' . QueryMonitor::icon( 'warning' ) . esc_html( sprintf(
|
||||
/* translators: An HTTP API request has disabled certificate verification. 1: Relevant argument name */
|
||||
__( 'Certificate verification disabled (%s)', 'query-monitor' ),
|
||||
'sslverify=false'
|
||||
) ) . '</span><br>';
|
||||
$url = preg_replace( '|^https:|', '<span class="qm-warn">https</span>:', $url );
|
||||
} elseif ( ! $is_error && $row['args']['blocking'] ) {
|
||||
$url = preg_replace( '|^https:|', '<span class="qm-true">https</span>:', $url );
|
||||
}
|
||||
}
|
||||
|
||||
$component = $row['component'];
|
||||
|
||||
$stack = array();
|
||||
$filtered_trace = $row['filtered_trace'];
|
||||
|
||||
foreach ( $filtered_trace as $frame ) {
|
||||
$stack[] = self::output_filename( $frame['display'], $frame['calling_file'], $frame['calling_line'] );
|
||||
}
|
||||
|
||||
$row_attr['data-qm-component'] = $component->name;
|
||||
$row_attr['data-qm-type'] = $row['type'];
|
||||
$row_attr['data-qm-time'] = $row['ltime'];
|
||||
$row_attr['data-qm-host'] = $row['host'];
|
||||
|
||||
if ( 'core' !== $component->context ) {
|
||||
$row_attr['data-qm-component'] .= ' non-core';
|
||||
}
|
||||
|
||||
$attr = '';
|
||||
foreach ( $row_attr as $a => $v ) {
|
||||
$attr .= ' ' . $a . '="' . esc_attr( (string) $v ) . '"';
|
||||
}
|
||||
|
||||
printf( // WPCS: XSS ok.
|
||||
'<tr %s class="%s">',
|
||||
$attr,
|
||||
esc_attr( $css )
|
||||
);
|
||||
printf(
|
||||
'<td>%s</td>',
|
||||
esc_html( $row['args']['method'] )
|
||||
);
|
||||
|
||||
if ( ! empty( $row['redirected_to'] ) ) {
|
||||
$url .= sprintf(
|
||||
'<br><span class="qm-warn">%1$s%2$s</span><br>%3$s',
|
||||
QueryMonitor::icon( 'warning' ),
|
||||
/* translators: An HTTP API request redirected to another URL */
|
||||
__( 'Redirected to:', 'query-monitor' ),
|
||||
self::format_url( $row['redirected_to'] )
|
||||
);
|
||||
}
|
||||
|
||||
printf( // WPCS: XSS ok.
|
||||
'<td class="qm-url qm-ltr qm-wrap">%s%s</td>',
|
||||
$info,
|
||||
$url
|
||||
);
|
||||
|
||||
$show_toggle = ! empty( $row['info'] );
|
||||
|
||||
echo '<td class="qm-has-toggle qm-col-status">';
|
||||
if ( $is_error ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo QueryMonitor::icon( 'warning' );
|
||||
}
|
||||
echo esc_html( $response );
|
||||
|
||||
if ( $show_toggle ) {
|
||||
echo self::build_toggler(); // WPCS: XSS ok;
|
||||
echo '<ul class="qm-toggled">';
|
||||
}
|
||||
|
||||
if ( ! empty( $row['info'] ) ) {
|
||||
$time_fields = array(
|
||||
'namelookup_time' => __( 'DNS Resolution Time', 'query-monitor' ),
|
||||
'connect_time' => __( 'Connection Time', 'query-monitor' ),
|
||||
'starttransfer_time' => __( 'Transfer Start Time (TTFB)', 'query-monitor' ),
|
||||
);
|
||||
foreach ( $time_fields as $key => $value ) {
|
||||
if ( ! isset( $row['info'][ $key ] ) ) {
|
||||
continue;
|
||||
}
|
||||
printf(
|
||||
'<li><span class="qm-info qm-supplemental">%1$s: %2$s</span></li>',
|
||||
esc_html( $value ),
|
||||
esc_html( number_format_i18n( $row['info'][ $key ], 4 ) )
|
||||
);
|
||||
}
|
||||
|
||||
$other_fields = array(
|
||||
'content_type' => __( 'Response Content Type', 'query-monitor' ),
|
||||
'primary_ip' => __( 'IP Address', 'query-monitor' ),
|
||||
);
|
||||
foreach ( $other_fields as $key => $value ) {
|
||||
if ( ! isset( $row['info'][ $key ] ) ) {
|
||||
continue;
|
||||
}
|
||||
printf(
|
||||
'<li><span class="qm-info qm-supplemental">%1$s: %2$s</span></li>',
|
||||
esc_html( $value ),
|
||||
esc_html( $row['info'][ $key ] )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( $show_toggle ) {
|
||||
echo '</ul>';
|
||||
}
|
||||
|
||||
echo '</td>';
|
||||
|
||||
$caller = array_shift( $stack );
|
||||
|
||||
echo '<td class="qm-has-toggle qm-nowrap qm-ltr">';
|
||||
|
||||
if ( ! empty( $stack ) ) {
|
||||
echo self::build_toggler(); // WPCS: XSS ok;
|
||||
}
|
||||
|
||||
echo '<ol>';
|
||||
|
||||
echo "<li>{$caller}</li>"; // WPCS: XSS ok.
|
||||
|
||||
if ( ! empty( $stack ) ) {
|
||||
echo '<div class="qm-toggled"><li>' . implode( '</li><li>', $stack ) . '</li></div>'; // WPCS: XSS ok.
|
||||
}
|
||||
|
||||
echo '</ol></td>';
|
||||
|
||||
printf(
|
||||
'<td class="qm-nowrap">%s</td>',
|
||||
esc_html( $component->name )
|
||||
);
|
||||
|
||||
$size = '';
|
||||
|
||||
if ( isset( $row['info']['size_download'] ) ) {
|
||||
$size = sprintf(
|
||||
/* translators: %s: Memory used in kilobytes */
|
||||
__( '%s kB', 'query-monitor' ),
|
||||
number_format_i18n( $row['info']['size_download'] / 1024, 1 )
|
||||
);
|
||||
}
|
||||
|
||||
printf(
|
||||
'<td class="qm-nowrap qm-num">%s</td>',
|
||||
esc_html( $size )
|
||||
);
|
||||
|
||||
printf(
|
||||
'<td class="qm-num">%s</td>',
|
||||
esc_html( $row['args']['timeout'] )
|
||||
);
|
||||
|
||||
if ( empty( $ltime ) ) {
|
||||
$stime = '';
|
||||
} else {
|
||||
$stime = number_format_i18n( $ltime, 4 );
|
||||
}
|
||||
|
||||
printf(
|
||||
'<td class="qm-num">%s</td>',
|
||||
esc_html( $stime )
|
||||
);
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
echo '<tfoot>';
|
||||
|
||||
$total_stime = number_format_i18n( $data->ltime, 4 );
|
||||
$count = count( $data->http );
|
||||
|
||||
echo '<tr>';
|
||||
printf(
|
||||
'<td colspan="7">%s</td>',
|
||||
sprintf(
|
||||
/* translators: %s: Number of HTTP API requests */
|
||||
esc_html( _nx( 'Total: %s', 'Total: %s', $count, 'HTTP API calls', 'query-monitor' ) ),
|
||||
'<span class="qm-items-number">' . esc_html( number_format_i18n( $count ) ) . '</span>'
|
||||
)
|
||||
);
|
||||
echo '<td class="qm-num qm-items-time">' . esc_html( $total_stime ) . '</td>';
|
||||
echo '</tr>';
|
||||
echo '</tfoot>';
|
||||
|
||||
$this->after_tabular_output();
|
||||
} else {
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
$notice = __( 'No HTTP API calls.', 'query-monitor' );
|
||||
echo $this->build_notice( $notice ); // WPCS: XSS ok.
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, string> $class
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function admin_class( array $class ) {
|
||||
/** @var QM_Data_HTTP $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( isset( $data->errors['alert'] ) ) {
|
||||
$class[] = 'qm-alert';
|
||||
}
|
||||
if ( isset( $data->errors['warning'] ) ) {
|
||||
$class[] = 'qm-warning';
|
||||
}
|
||||
|
||||
return $class;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function admin_menu( array $menu ) {
|
||||
/** @var QM_Data_HTTP $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
$count = ! empty( $data->http ) ? count( $data->http ) : 0;
|
||||
|
||||
$title = ( empty( $count ) )
|
||||
? __( 'HTTP API Calls', 'query-monitor' )
|
||||
/* translators: %s: Number of calls to the HTTP API */
|
||||
: __( 'HTTP API Calls (%s)', 'query-monitor' );
|
||||
|
||||
$args = array(
|
||||
'title' => esc_html( sprintf(
|
||||
$title,
|
||||
number_format_i18n( $count )
|
||||
) ),
|
||||
);
|
||||
|
||||
if ( isset( $data->errors['alert'] ) ) {
|
||||
$args['meta']['classname'] = 'qm-alert';
|
||||
}
|
||||
if ( isset( $data->errors['warning'] ) ) {
|
||||
$args['meta']['classname'] = 'qm-warning';
|
||||
}
|
||||
|
||||
$menu[ $this->collector->id() ] = $this->menu( $args );
|
||||
|
||||
return $menu;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_http( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'http' );
|
||||
if ( $collector ) {
|
||||
$output['http'] = new QM_Output_Html_HTTP( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_http', 90, 2 );
|
212
wp-content/plugins/query-monitor/output/html/languages.php
Normal file
212
wp-content/plugins/query-monitor/output/html/languages.php
Normal file
@ -0,0 +1,212 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Language and locale output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Languages extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Languages Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 80 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Languages', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_Languages $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3><code>get_locale()</code></h3>';
|
||||
echo '<p>' . esc_html( $data->locale ) . '</p>';
|
||||
echo '</section>';
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3><code>get_user_locale()</code></h3>';
|
||||
echo '<p>' . esc_html( $data->user_locale ) . '</p>';
|
||||
echo '</section>';
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3><code>determine_locale()</code></h3>';
|
||||
echo '<p>' . esc_html( $data->determined_locale ) . '</p>';
|
||||
echo '</section>';
|
||||
|
||||
if ( isset( $data->mlp_language ) ) {
|
||||
echo '<section>';
|
||||
echo '<h3>';
|
||||
printf(
|
||||
/* translators: %s: Name of a multilingual plugin */
|
||||
esc_html__( '%s Language', 'query-monitor' ),
|
||||
'MultilingualPress'
|
||||
);
|
||||
echo '</h3>';
|
||||
echo '<p>' . esc_html( $data->mlp_language ) . '</p>';
|
||||
echo '</section>';
|
||||
}
|
||||
|
||||
if ( isset( $data->pll_language ) ) {
|
||||
echo '<section>';
|
||||
echo '<h3>';
|
||||
printf(
|
||||
/* translators: %s: Name of a multilingual plugin */
|
||||
esc_html__( '%s Language', 'query-monitor' ),
|
||||
'Polylang'
|
||||
);
|
||||
echo '</h3>';
|
||||
echo '<p>' . esc_html( $data->pll_language ) . '</p>';
|
||||
echo '</section>';
|
||||
}
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3><code>get_language_attributes()</code></h3>';
|
||||
echo '<p><code>' . esc_html( $data->language_attributes ) . '</code></p>';
|
||||
echo '</section>';
|
||||
|
||||
if ( ! empty( $data->languages ) ) {
|
||||
echo '<table class="qm-full-width">';
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col">' . esc_html__( 'Text Domain', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Type', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Caller', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Translation File', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Size', 'query-monitor' ) . '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
|
||||
echo '<tbody>';
|
||||
|
||||
foreach ( $data->languages as $textdomain => $mofiles ) {
|
||||
foreach ( $mofiles as $mofile ) {
|
||||
echo '<tr>';
|
||||
|
||||
if ( $mofile['handle'] ) {
|
||||
echo '<td class="qm-ltr">' . esc_html( $mofile['domain'] ) . ' (' . esc_html( $mofile['handle'] ) . ')</td>';
|
||||
} else {
|
||||
echo '<td class="qm-ltr">' . esc_html( $mofile['domain'] ) . '</td>';
|
||||
}
|
||||
|
||||
echo '<td>' . esc_html( $mofile['type'] ) . '</td>';
|
||||
|
||||
if ( self::has_clickable_links() ) {
|
||||
echo '<td class="qm-nowrap qm-ltr">';
|
||||
echo self::output_filename( $mofile['caller']['display'], $mofile['caller']['file'], $mofile['caller']['line'] ); // WPCS: XSS ok.
|
||||
echo '</td>';
|
||||
} else {
|
||||
echo '<td class="qm-nowrap qm-ltr qm-has-toggle">';
|
||||
echo self::build_toggler(); // WPCS: XSS ok;
|
||||
echo '<ol>';
|
||||
echo '<li>';
|
||||
// undefined:
|
||||
echo self::output_filename( $mofile['caller']['display'], $mofile['caller']['file'], $mofile['caller']['line'] ); // WPCS: XSS ok.
|
||||
echo '</li>';
|
||||
echo '</ol></td>';
|
||||
}
|
||||
|
||||
echo '<td class="qm-ltr">';
|
||||
if ( $mofile['file'] ) {
|
||||
if ( $mofile['found'] && 'jed' === $mofile['type'] && self::has_clickable_links() ) {
|
||||
echo self::output_filename( QM_Util::standard_dir( $mofile['file'], '' ), $mofile['file'], 1, true ); // WPCS: XSS ok.
|
||||
} else {
|
||||
echo esc_html( QM_Util::standard_dir( $mofile['file'], '' ) );
|
||||
}
|
||||
} else {
|
||||
echo '<em>' . esc_html__( 'None', 'query-monitor' ) . '</em>';
|
||||
}
|
||||
echo '</td>';
|
||||
|
||||
if ( $mofile['found'] ) {
|
||||
echo '<td class="qm-nowrap qm-num">';
|
||||
echo esc_html( sprintf(
|
||||
/* translators: %s: Memory used in kilobytes */
|
||||
__( '%s kB', 'query-monitor' ),
|
||||
number_format_i18n( $mofile['found'] / 1024, 1 )
|
||||
) );
|
||||
echo '</td>';
|
||||
} else {
|
||||
echo '<td class="qm-nowrap">';
|
||||
echo esc_html__( 'Not Found', 'query-monitor' );
|
||||
echo '</td>';
|
||||
}
|
||||
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
|
||||
echo '<tfoot>';
|
||||
echo '<tr>';
|
||||
echo '<td colspan="4"> </td>';
|
||||
echo '<td class="qm-num">';
|
||||
|
||||
echo esc_html( sprintf(
|
||||
/* translators: %s: Memory used in kilobytes */
|
||||
__( '%s kB', 'query-monitor' ),
|
||||
number_format_i18n( $data->total_size / 1024, 1 )
|
||||
) );
|
||||
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
echo '</tfoot>';
|
||||
|
||||
echo '</table>';
|
||||
}
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function admin_menu( array $menu ) {
|
||||
$args = array(
|
||||
'title' => esc_html( $this->name() ),
|
||||
);
|
||||
|
||||
$menu[ $this->collector->id() ] = $this->menu( $args );
|
||||
|
||||
return $menu;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_languages( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'languages' );
|
||||
if ( $collector ) {
|
||||
$output['languages'] = new QM_Output_Html_Languages( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_languages', 81, 2 );
|
249
wp-content/plugins/query-monitor/output/html/logger.php
Normal file
249
wp-content/plugins/query-monitor/output/html/logger.php
Normal file
@ -0,0 +1,249 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* PSR-3 compatible logging output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Logger extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Logger Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 47 );
|
||||
add_filter( 'qm/output/menu_class', array( $this, 'admin_class' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Logger', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_Logger $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->logs ) ) {
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
$notice = sprintf(
|
||||
/* translators: %s: Link to help article */
|
||||
__( 'No data logged. <a href="%s">Read about logging variables in Query Monitor</a>.', 'query-monitor' ),
|
||||
'https://querymonitor.com/docs/logging-variables/'
|
||||
);
|
||||
echo $this->build_notice( $notice ); // WPCS: XSS ok.
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$levels = array();
|
||||
|
||||
foreach ( $this->collector->get_levels() as $level ) {
|
||||
if ( $data->counts[ $level ] ) {
|
||||
$levels[ $level ] = sprintf(
|
||||
'%s (%d)',
|
||||
ucfirst( $level ),
|
||||
$data->counts[ $level ]
|
||||
);
|
||||
} else {
|
||||
$levels[ $level ] = ucfirst( $level );
|
||||
}
|
||||
}
|
||||
|
||||
$this->before_tabular_output();
|
||||
|
||||
$level_args = array(
|
||||
'all' => sprintf(
|
||||
/* translators: %s: Total number of items in a list */
|
||||
__( 'All (%d)', 'query-monitor' ),
|
||||
count( $data->logs )
|
||||
),
|
||||
);
|
||||
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
echo $this->build_filter( 'type', $levels, __( 'Level', 'query-monitor' ), $level_args ); // WPCS: XSS ok.
|
||||
echo '</th>';
|
||||
echo '<th scope="col" class="qm-col-message">' . esc_html__( 'Message', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Caller', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
echo $this->build_filter( 'component', $data->components, __( 'Component', 'query-monitor' ) ); // WPCS: XSS ok.
|
||||
echo '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
|
||||
echo '<tbody>';
|
||||
|
||||
foreach ( $data->logs as $row ) {
|
||||
$component = $row['component'];
|
||||
|
||||
$row_attr = array();
|
||||
$row_attr['data-qm-component'] = $component->name;
|
||||
$row_attr['data-qm-type'] = $row['level'];
|
||||
|
||||
$attr = '';
|
||||
|
||||
foreach ( $row_attr as $a => $v ) {
|
||||
$attr .= ' ' . $a . '="' . esc_attr( $v ) . '"';
|
||||
}
|
||||
|
||||
$is_warning = in_array( $row['level'], $this->collector->get_warning_levels(), true );
|
||||
|
||||
if ( $is_warning ) {
|
||||
$class = 'qm-warn';
|
||||
} else {
|
||||
$class = '';
|
||||
}
|
||||
|
||||
echo '<tr' . $attr . ' class="' . esc_attr( $class ) . '">'; // WPCS: XSS ok.
|
||||
|
||||
echo '<td class="qm-nowrap">';
|
||||
|
||||
if ( $is_warning ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo QueryMonitor::icon( 'warning' );
|
||||
} else {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo QueryMonitor::icon( 'blank' );
|
||||
}
|
||||
|
||||
echo esc_html( ucfirst( $row['level'] ) );
|
||||
echo '</td>';
|
||||
|
||||
printf(
|
||||
'<td><pre>%s</pre></td>',
|
||||
esc_html( $row['message'] )
|
||||
);
|
||||
|
||||
$stack = array();
|
||||
$filtered_trace = $row['filtered_trace'];
|
||||
|
||||
foreach ( $filtered_trace as $frame ) {
|
||||
$stack[] = self::output_filename( $frame['display'], $frame['calling_file'], $frame['calling_line'] );
|
||||
}
|
||||
|
||||
$caller = array_shift( $stack );
|
||||
|
||||
echo '<td class="qm-has-toggle qm-nowrap qm-ltr">';
|
||||
|
||||
if ( ! empty( $stack ) ) {
|
||||
echo self::build_toggler(); // WPCS: XSS ok;
|
||||
}
|
||||
|
||||
echo '<ol>';
|
||||
|
||||
echo "<li>{$caller}</li>"; // WPCS: XSS ok.
|
||||
|
||||
if ( ! empty( $stack ) ) {
|
||||
echo '<div class="qm-toggled"><li>' . implode( '</li><li>', $stack ) . '</li></div>'; // WPCS: XSS ok.
|
||||
}
|
||||
|
||||
echo '</ol></td>';
|
||||
|
||||
printf(
|
||||
'<td class="qm-nowrap">%s</td>',
|
||||
esc_html( $component->name )
|
||||
);
|
||||
|
||||
echo '</tr>';
|
||||
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
|
||||
$this->after_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, string> $class
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function admin_class( array $class ) {
|
||||
/** @var QM_Data_Logger $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->logs ) ) {
|
||||
return $class;
|
||||
}
|
||||
|
||||
foreach ( $data->logs as $log ) {
|
||||
if ( in_array( $log['level'], $this->collector->get_warning_levels(), true ) ) {
|
||||
$class[] = 'qm-warning';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function admin_menu( array $menu ) {
|
||||
/** @var QM_Data_Logger $data */
|
||||
$data = $this->collector->get_data();
|
||||
$key = 'log';
|
||||
$count = 0;
|
||||
|
||||
if ( ! empty( $data->logs ) ) {
|
||||
foreach ( $data->logs as $log ) {
|
||||
if ( in_array( $log['level'], $this->collector->get_warning_levels(), true ) ) {
|
||||
$key = 'warning';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$count = count( $data->logs );
|
||||
|
||||
/* translators: %s: Number of logs that are available */
|
||||
$label = __( 'Logs (%s)', 'query-monitor' );
|
||||
} else {
|
||||
$label = __( 'Logs', 'query-monitor' );
|
||||
}
|
||||
|
||||
$menu[ $this->collector->id() ] = $this->menu( array(
|
||||
'id' => "query-monitor-logger-{$key}",
|
||||
'title' => esc_html( sprintf(
|
||||
$label,
|
||||
number_format_i18n( $count )
|
||||
) ),
|
||||
) );
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_logger( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'logger' );
|
||||
if ( $collector ) {
|
||||
$output['logger'] = new QM_Output_Html_Logger( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_logger', 12, 2 );
|
167
wp-content/plugins/query-monitor/output/html/multisite.php
Normal file
167
wp-content/plugins/query-monitor/output/html/multisite.php
Normal file
@ -0,0 +1,167 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Multisite output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Multisite extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Multisite Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 55 );
|
||||
}
|
||||
|
||||
public function name() {
|
||||
return __( 'Multisite', 'query-monitor' );
|
||||
}
|
||||
|
||||
public function output() {
|
||||
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data['switches'] ) ) {
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
$notice = __( 'No data logged.', 'query-monitor' );
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $this->build_notice( $notice );
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->before_tabular_output();
|
||||
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col" class="qm-num">#</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Function', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Site Switch', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Caller', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $this->build_filter( 'component', array(), __( 'Component', 'query-monitor' ) );
|
||||
echo '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
|
||||
echo '<tbody>';
|
||||
|
||||
$i = 0;
|
||||
|
||||
foreach ( $data['switches'] as $row ) {
|
||||
$component = $row['trace']->get_component();
|
||||
|
||||
$row_attr = array();
|
||||
$row_attr['data-qm-component'] = $component->name;
|
||||
|
||||
$attr = '';
|
||||
|
||||
foreach ( $row_attr as $a => $v ) {
|
||||
$attr .= ' ' . $a . '="' . esc_attr( $v ) . '"';
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<tr' . $attr . '>';
|
||||
|
||||
echo '<td class="qm-num">';
|
||||
if ( $row['to'] ) {
|
||||
echo intval( ++$i );
|
||||
}
|
||||
echo '</td>';
|
||||
|
||||
echo '<td class="qm-nowrap"><code>';
|
||||
if ( $row['to'] ) {
|
||||
printf(
|
||||
'switch_to_blog(%d)',
|
||||
intval($row['new'] )
|
||||
);
|
||||
} else {
|
||||
echo 'restore_current_blog()';
|
||||
}
|
||||
echo '</code></td>';
|
||||
|
||||
echo '<td class="qm-nowrap">';
|
||||
if ( $row['to'] ) {
|
||||
echo esc_html( sprintf(
|
||||
'%1$s → %2$s',
|
||||
$row['prev'],
|
||||
$row['new']
|
||||
) );
|
||||
} else {
|
||||
echo esc_html( sprintf(
|
||||
'%1$s ← %2$s',
|
||||
$row['new'],
|
||||
$row['prev']
|
||||
) );
|
||||
}
|
||||
echo '</td>';
|
||||
|
||||
$stack = array();
|
||||
$filtered_trace = $row['trace']->get_display_trace();
|
||||
|
||||
foreach ( $filtered_trace as $item ) {
|
||||
$stack[] = self::output_filename( $item['display'], $item['calling_file'], $item['calling_line'] );
|
||||
}
|
||||
|
||||
$caller = array_shift( $stack );
|
||||
|
||||
echo '<td class="qm-has-toggle qm-nowrap qm-ltr">';
|
||||
|
||||
if ( ! empty( $stack ) ) {
|
||||
echo self::build_toggler(); // WPCS: XSS ok;
|
||||
}
|
||||
|
||||
echo '<ol>';
|
||||
|
||||
echo "<li>{$caller}</li>"; // WPCS: XSS ok.
|
||||
|
||||
if ( ! empty( $stack ) ) {
|
||||
echo '<div class="qm-toggled"><li>' . implode( '</li><li>', $stack ) . '</li></div>'; // WPCS: XSS ok.
|
||||
}
|
||||
|
||||
echo '</ol></td>';
|
||||
|
||||
printf(
|
||||
'<td class="qm-nowrap">%s</td>',
|
||||
esc_html( $component->name )
|
||||
);
|
||||
|
||||
echo '</tr>';
|
||||
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
|
||||
$this->after_tabular_output();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_multisite( array $output, QM_Collectors $collectors ) {
|
||||
$collector = is_multisite() ? QM_Collectors::get( 'multisite' ) : null;
|
||||
|
||||
if ( $collector ) {
|
||||
$output['multisite'] = new QM_Output_Html_Multisite( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_multisite', 65, 2 );
|
413
wp-content/plugins/query-monitor/output/html/overview.php
Normal file
413
wp-content/plugins/query-monitor/output/html/overview.php
Normal file
@ -0,0 +1,413 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* General overview output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Overview extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Overview Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/title', array( $this, 'admin_title' ), 10 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Overview', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_Overview $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
$db_query_num = null;
|
||||
/** @var QM_Collector_DB_Queries|null $db_queries */
|
||||
$db_queries = QM_Collectors::get( 'db_queries' );
|
||||
|
||||
if ( $db_queries ) {
|
||||
/** @var QM_Data_DB_Queries $db_queries_data */
|
||||
$db_queries_data = $db_queries->get_data();
|
||||
if ( ! empty( $db_queries_data->types ) ) {
|
||||
$db_query_num = $db_queries_data->types;
|
||||
}
|
||||
}
|
||||
|
||||
/** @var QM_Collector_Raw_Request|null $raw_request */
|
||||
$raw_request = QM_Collectors::get( 'raw_request' );
|
||||
|
||||
/** @var QM_Collector_Cache|null $cache */
|
||||
$cache = QM_Collectors::get( 'cache' );
|
||||
|
||||
/** @var QM_Collector_HTTP|null $http */
|
||||
$http = QM_Collectors::get( 'http' );
|
||||
|
||||
$qm_broken = __( 'A JavaScript problem on the page is preventing Query Monitor from working correctly. jQuery may have been blocked from loading.', 'query-monitor' );
|
||||
$ajax_errors = __( 'PHP errors were triggered during an Ajax request. See your browser developer console for details.', 'query-monitor' );
|
||||
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
echo '<section id="qm-broken">';
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<p class="qm-warn">' . QueryMonitor::icon( 'warning' ) . esc_html( $qm_broken ) . '</p>';
|
||||
echo '</section>';
|
||||
|
||||
echo '<section id="qm-ajax-errors">';
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<p class="qm-warn">' . QueryMonitor::icon( 'warning' ) . esc_html( $ajax_errors ) . '</p>';
|
||||
echo '</section>';
|
||||
|
||||
if ( $raw_request ) {
|
||||
echo '<section id="qm-overview-raw-request">';
|
||||
/** @var QM_Data_Raw_Request $raw_data */
|
||||
$raw_data = $raw_request->get_data();
|
||||
|
||||
if ( ! empty( $raw_data->response['status'] ) ) {
|
||||
$status = $raw_data->response['status'];
|
||||
} else {
|
||||
$status = __( 'Unknown HTTP Response Code', 'query-monitor' );
|
||||
}
|
||||
|
||||
printf(
|
||||
'<h3>%1$s %2$s → %3$s</h3>',
|
||||
esc_html( $raw_data->request['method'] ),
|
||||
esc_html( $raw_data->request['url'] ),
|
||||
esc_html( $status )
|
||||
);
|
||||
echo '</section>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
echo '<div class="qm-grid">';
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'Page Generation Time', 'query-monitor' ) . '</h3>';
|
||||
echo '<p>';
|
||||
echo esc_html(
|
||||
sprintf(
|
||||
/* translators: %s: A time in seconds with a decimal fraction. No space between value and unit. */
|
||||
_x( '%ss', 'Time in seconds', 'query-monitor' ),
|
||||
number_format_i18n( $data->time_taken, 4 )
|
||||
)
|
||||
);
|
||||
|
||||
if ( $data->time_limit > 0 ) {
|
||||
if ( $data->display_time_usage_warning ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<br><span class="qm-warn">' . QueryMonitor::icon( 'warning' );
|
||||
} else {
|
||||
echo '<br><span class="qm-info">';
|
||||
}
|
||||
echo esc_html( sprintf(
|
||||
/* translators: 1: Percentage of time limit used, 2: Time limit in seconds */
|
||||
__( '%1$s%% of %2$ss limit', 'query-monitor' ),
|
||||
number_format_i18n( $data->time_usage, 1 ),
|
||||
number_format_i18n( $data->time_limit )
|
||||
) );
|
||||
echo '</span>';
|
||||
} else {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<br><span class="qm-warn">' . QueryMonitor::icon( 'warning' );
|
||||
printf(
|
||||
/* translators: 1: Name of the PHP directive, 2: Value of the PHP directive */
|
||||
esc_html__( 'No execution time limit. The %1$s PHP configuration directive is set to %2$s.', 'query-monitor' ),
|
||||
'<code>max_execution_time</code>',
|
||||
'0'
|
||||
);
|
||||
echo '</span>';
|
||||
}
|
||||
echo '</p>';
|
||||
echo '</section>';
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'Peak Memory Usage', 'query-monitor' ) . '</h3>';
|
||||
echo '<p>';
|
||||
|
||||
if ( empty( $data->memory ) ) {
|
||||
esc_html_e( 'Unknown', 'query-monitor' );
|
||||
} else {
|
||||
echo esc_html( sprintf(
|
||||
/* translators: 1: Memory used in bytes, 2: Memory used in megabytes */
|
||||
__( '%1$s bytes (%2$s MB)', 'query-monitor' ),
|
||||
number_format_i18n( $data->memory ),
|
||||
number_format_i18n( ( $data->memory / 1024 / 1024 ), 1 )
|
||||
) );
|
||||
|
||||
if ( $data->memory_limit > 0 ) {
|
||||
if ( $data->display_memory_usage_warning ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<br><span class="qm-warn">' . QueryMonitor::icon( 'warning' );
|
||||
} else {
|
||||
echo '<br><span class="qm-info">';
|
||||
}
|
||||
echo esc_html( sprintf(
|
||||
/* translators: 1: Percentage of memory limit used, 2: Memory limit in megabytes */
|
||||
__( '%1$s%% of %2$s MB server limit', 'query-monitor' ),
|
||||
number_format_i18n( $data->memory_usage, 1 ),
|
||||
number_format_i18n( $data->memory_limit / 1024 / 1024 )
|
||||
) );
|
||||
echo '</span>';
|
||||
} else {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<br><span class="qm-warn">' . QueryMonitor::icon( 'warning' );
|
||||
printf(
|
||||
/* translators: 1: Name of the PHP directive, 2: Value of the PHP directive */
|
||||
esc_html__( 'No memory limit. The %1$s PHP configuration directive is set to %2$s.', 'query-monitor' ),
|
||||
'<code>memory_limit</code>',
|
||||
'0'
|
||||
);
|
||||
echo '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '</p>';
|
||||
echo '</section>';
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'Database Queries', 'query-monitor' ) . '</h3>';
|
||||
|
||||
if ( isset( $db_query_num, $db_queries_data ) ) {
|
||||
echo '<p>';
|
||||
echo esc_html(
|
||||
sprintf(
|
||||
/* translators: %s: A time in seconds with a decimal fraction. No space between value and unit. */
|
||||
_x( '%ss', 'Time in seconds', 'query-monitor' ),
|
||||
number_format_i18n( $db_queries_data->total_time, 4 )
|
||||
)
|
||||
);
|
||||
echo '</p>';
|
||||
|
||||
echo '<p>';
|
||||
|
||||
if ( ! isset( $db_query_num['SELECT'] ) || count( $db_query_num ) > 1 ) {
|
||||
foreach ( $db_query_num as $type_name => $type_count ) {
|
||||
$label = sprintf(
|
||||
'%1$s: %2$s',
|
||||
esc_html( $type_name ),
|
||||
esc_html( number_format_i18n( $type_count ) )
|
||||
);
|
||||
echo self::build_filter_trigger( 'db_queries', 'type', (string) $type_name, esc_html( $label ) ); // WPCS: XSS ok;
|
||||
echo '<br>';
|
||||
}
|
||||
}
|
||||
|
||||
$label = sprintf(
|
||||
'%1$s: %2$s',
|
||||
esc_html( _x( 'Total', 'database queries', 'query-monitor' ) ),
|
||||
esc_html( number_format_i18n( $db_queries_data->total_qs ) )
|
||||
);
|
||||
echo self::build_filter_trigger( 'db_queries', 'type', '', esc_html( $label ) ); // WPCS: XSS ok;
|
||||
|
||||
echo '</p>';
|
||||
} else {
|
||||
printf(
|
||||
'<p><em>%s</em></p>',
|
||||
esc_html__( 'None', 'query-monitor' )
|
||||
);
|
||||
}
|
||||
|
||||
echo '</section>';
|
||||
|
||||
if ( $http ) {
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'HTTP API Calls', 'query-monitor' ) . '</h3>';
|
||||
|
||||
$http_data = $http->get_data();
|
||||
|
||||
if ( ! empty( $http_data->http ) ) {
|
||||
echo '<p>';
|
||||
echo esc_html(
|
||||
sprintf(
|
||||
/* translators: %s: A time in seconds with a decimal fraction. No space between value and unit. */
|
||||
_x( '%ss', 'Time in seconds', 'query-monitor' ),
|
||||
number_format_i18n( $http_data->ltime, 4 )
|
||||
)
|
||||
);
|
||||
echo '</p>';
|
||||
|
||||
$label = sprintf(
|
||||
'%1$s: %2$s',
|
||||
esc_html( _x( 'Total', 'HTTP API calls', 'query-monitor' ) ),
|
||||
esc_html( number_format_i18n( count( $http_data->http ) ) )
|
||||
);
|
||||
echo self::build_filter_trigger( 'http', 'type', '', esc_html( $label ) ); // WPCS: XSS ok;
|
||||
} else {
|
||||
printf(
|
||||
'<p><em>%s</em></p>',
|
||||
esc_html__( 'None', 'query-monitor' )
|
||||
);
|
||||
}
|
||||
|
||||
echo '</section>';
|
||||
}
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'Object Cache', 'query-monitor' ) . '</h3>';
|
||||
|
||||
if ( $cache ) {
|
||||
/** @var QM_Data_Cache $cache_data */
|
||||
$cache_data = $cache->get_data();
|
||||
|
||||
if ( ! empty( $cache_data->stats ) && ! empty( $cache_data->cache_hit_percentage ) ) {
|
||||
$cache_hit_percentage = $cache_data->cache_hit_percentage;
|
||||
|
||||
echo '<p>';
|
||||
echo esc_html( sprintf(
|
||||
/* translators: 1: Cache hit rate percentage, 2: number of cache hits, 3: number of cache misses */
|
||||
__( '%1$s%% hit rate (%2$s hits, %3$s misses)', 'query-monitor' ),
|
||||
number_format_i18n( $cache_hit_percentage, 1 ),
|
||||
number_format_i18n( $cache_data->stats['cache_hits'], 0 ),
|
||||
number_format_i18n( $cache_data->stats['cache_misses'], 0 )
|
||||
) );
|
||||
echo '</p>';
|
||||
}
|
||||
|
||||
if ( $cache_data->has_object_cache ) {
|
||||
echo '<p><span class="qm-info">';
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo self::build_link(
|
||||
network_admin_url( 'plugins.php?plugin_status=dropins' ),
|
||||
esc_html__( 'Persistent object cache plugin in use', 'query-monitor' )
|
||||
);
|
||||
echo '</span></p>';
|
||||
} else {
|
||||
echo '<p><span class="qm-warn">';
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo QueryMonitor::icon( 'warning' );
|
||||
echo esc_html__( 'Persistent object cache plugin not in use', 'query-monitor' );
|
||||
echo '</span></p>';
|
||||
|
||||
$potentials = array_filter( $cache_data->object_cache_extensions );
|
||||
|
||||
if ( ! empty( $potentials ) ) {
|
||||
foreach ( $potentials as $name => $value ) {
|
||||
$url = sprintf(
|
||||
'https://wordpress.org/plugins/search/%s/',
|
||||
strtolower( $name )
|
||||
);
|
||||
echo '<p>';
|
||||
echo wp_kses(
|
||||
sprintf(
|
||||
/* translators: 1: PHP extension name, 2: URL to plugin directory */
|
||||
__( 'The %1$s object cache extension for PHP is installed but is not in use by WordPress. You should <a href="%2$s" target="_blank" class="qm-external-link">install a %1$s plugin</a>.', 'query-monitor' ),
|
||||
esc_html( $name ),
|
||||
esc_url( $url )
|
||||
),
|
||||
array(
|
||||
'a' => array(
|
||||
'href' => array(),
|
||||
'target' => array(),
|
||||
'class' => array(),
|
||||
),
|
||||
)
|
||||
);
|
||||
echo '</p>';
|
||||
}
|
||||
} else {
|
||||
echo '<p>';
|
||||
echo esc_html__( 'Speak to your web host about enabling an object cache extension such as Redis or Memcached.', 'query-monitor' );
|
||||
echo '</p>';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo '<p>';
|
||||
echo esc_html__( 'Object cache statistics are not available', 'query-monitor' );
|
||||
echo '</p>';
|
||||
}
|
||||
|
||||
echo '</section>';
|
||||
|
||||
if ( $cache ) {
|
||||
/** @var QM_Data_Cache $cache_data */
|
||||
$cache_data = $cache->get_data();
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'Opcode Cache', 'query-monitor' ) . '</h3>';
|
||||
|
||||
if ( $cache_data->has_opcode_cache ) {
|
||||
foreach ( array_filter( $cache_data->opcode_cache_extensions ) as $opcache_name => $opcache_state ) {
|
||||
echo '<p>';
|
||||
echo esc_html( sprintf(
|
||||
/* translators: %s: Name of cache driver */
|
||||
__( 'Opcode cache in use: %s', 'query-monitor' ),
|
||||
$opcache_name
|
||||
) );
|
||||
echo '</p>';
|
||||
}
|
||||
} else {
|
||||
echo '<p><span class="qm-warn">';
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo QueryMonitor::icon( 'warning' );
|
||||
echo esc_html__( 'Opcode cache not in use', 'query-monitor' );
|
||||
echo '</span></p>';
|
||||
echo '<p>';
|
||||
echo esc_html__( 'Speak to your web host about enabling an opcode cache such as OPcache.', 'query-monitor' );
|
||||
echo '</p>';
|
||||
}
|
||||
|
||||
echo '</section>';
|
||||
}
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, string> $title
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function admin_title( array $title ) {
|
||||
/** @var QM_Data_Overview $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->memory ) ) {
|
||||
$memory = '??';
|
||||
} else {
|
||||
$memory = number_format_i18n( ( $data->memory / 1024 / 1024 ), 1 );
|
||||
}
|
||||
|
||||
$title[] = sprintf(
|
||||
/* translators: %s: A time in seconds with a decimal fraction. No space between value and unit symbol. */
|
||||
esc_html_x( '%ss', 'Time in seconds', 'query-monitor' ),
|
||||
number_format_i18n( $data->time_taken, 2 )
|
||||
);
|
||||
$title[] = preg_replace( '#\s?([^0-9,\.]+)#', '<small>$1</small>', sprintf(
|
||||
/* translators: %s: Memory usage in megabytes with a decimal fraction. Note the space between value and unit symbol. */
|
||||
esc_html__( '%s MB', 'query-monitor' ),
|
||||
$memory
|
||||
) );
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_overview( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'overview' );
|
||||
if ( $collector ) {
|
||||
$output['overview'] = new QM_Output_Html_Overview( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_overview', 10, 2 );
|
349
wp-content/plugins/query-monitor/output/html/php_errors.php
Normal file
349
wp-content/plugins/query-monitor/output/html/php_errors.php
Normal file
@ -0,0 +1,349 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* PHP error output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_PHP_Errors extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_PHP_Errors Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 10 );
|
||||
add_filter( 'qm/output/panel_menus', array( $this, 'panel_menu' ), 10 );
|
||||
add_filter( 'qm/output/menu_class', array( $this, 'admin_class' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'PHP Errors', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_PHP_Errors $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->errors ) && empty( $data->silenced ) && empty( $data->suppressed ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$levels = array(
|
||||
'Warning',
|
||||
'Notice',
|
||||
'Strict',
|
||||
'Deprecated',
|
||||
);
|
||||
$components = $data->components;
|
||||
$count = 0;
|
||||
|
||||
usort( $components, 'strcasecmp' );
|
||||
|
||||
$this->before_tabular_output();
|
||||
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
echo $this->build_filter( 'type', $levels, __( 'Level', 'query-monitor' ) ); // WPCS: XSS ok.
|
||||
echo '</th>';
|
||||
echo '<th scope="col" class="qm-col-message">' . esc_html__( 'Message', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Location', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col" class="qm-num">' . esc_html__( 'Count', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col" class="qm-filterable-column">';
|
||||
echo $this->build_filter( 'component', $components, __( 'Component', 'query-monitor' ) ); // WPCS: XSS ok.
|
||||
echo '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
|
||||
echo '<tbody>';
|
||||
|
||||
foreach ( $this->collector->types as $error_group => $error_types ) {
|
||||
foreach ( $error_types as $type => $title ) {
|
||||
|
||||
if ( ! isset( $data->{$error_group}[ $type ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $data->{$error_group}[ $type ] as $error_key => $error ) {
|
||||
$count += $error['calls'];
|
||||
|
||||
$row_attr = array();
|
||||
$row_attr['data-qm-type'] = ucfirst( $type );
|
||||
$row_attr['data-qm-key'] = $error_key;
|
||||
$row_attr['data-qm-count'] = $error['calls'];
|
||||
|
||||
if ( $error['component'] ) {
|
||||
$component = $error['component'];
|
||||
$row_attr['data-qm-component'] = $component->name;
|
||||
|
||||
if ( 'core' !== $component->context ) {
|
||||
$row_attr['data-qm-component'] .= ' non-core';
|
||||
}
|
||||
}
|
||||
|
||||
$attr = '';
|
||||
|
||||
foreach ( $row_attr as $a => $v ) {
|
||||
$attr .= ' ' . $a . '="' . esc_attr( $v ) . '"';
|
||||
}
|
||||
|
||||
$is_warning = ( 'errors' === $error_group && 'warning' === $type );
|
||||
|
||||
if ( $is_warning ) {
|
||||
$class = 'qm-warn';
|
||||
} else {
|
||||
$class = '';
|
||||
}
|
||||
|
||||
echo '<tr ' . $attr . 'class="' . esc_attr( $class ) . '">'; // WPCS: XSS ok.
|
||||
echo '<td class="qm-nowrap">';
|
||||
|
||||
if ( $is_warning ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo QueryMonitor::icon( 'warning' );
|
||||
} else {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo QueryMonitor::icon( 'blank' );
|
||||
}
|
||||
|
||||
echo esc_html( $title );
|
||||
echo '</td>';
|
||||
|
||||
echo '<td class="qm-ltr">' . esc_html( $error['message'] ) . '</td>';
|
||||
|
||||
$stack = array();
|
||||
|
||||
if ( $error['filtered_trace'] ) {
|
||||
$filtered_trace = $error['filtered_trace'];
|
||||
|
||||
// debug_backtrace() (used within QM_Backtrace) doesn't like being used within an error handler so
|
||||
// we need to handle its somewhat unreliable stack trace items.
|
||||
// https://bugs.php.net/bug.php?id=39070
|
||||
// https://bugs.php.net/bug.php?id=64987
|
||||
foreach ( $filtered_trace as $i => $item ) {
|
||||
if ( isset( $item['file'], $item['line'] ) ) {
|
||||
$stack[] = self::output_filename( $item['display'], $item['file'], $item['line'] );
|
||||
} elseif ( 0 === $i ) {
|
||||
$stack[] = self::output_filename( $item['display'], $error['file'], $error['line'] );
|
||||
} else {
|
||||
$stack[] = $item['display'] . '<br><span class="qm-info qm-supplemental"><em>' . __( 'Unknown location', 'query-monitor' ) . '</em></span>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo '<td class="qm-row-caller qm-row-stack qm-nowrap qm-ltr qm-has-toggle">';
|
||||
|
||||
if ( ! empty( $stack ) ) {
|
||||
echo self::build_toggler(); // WPCS: XSS ok;
|
||||
}
|
||||
|
||||
echo '<ol>';
|
||||
echo '<li>';
|
||||
echo self::output_filename( $error['filename'] . ':' . $error['line'], $error['file'], $error['line'], true ); // WPCS: XSS ok.
|
||||
echo '</li>';
|
||||
|
||||
if ( ! empty( $stack ) ) {
|
||||
echo '<div class="qm-toggled"><li>' . implode( '</li><li>', $stack ) . '</li></div>'; // WPCS: XSS ok.
|
||||
}
|
||||
|
||||
echo '</ol></td>';
|
||||
echo '<td class="qm-num">' . esc_html( number_format_i18n( $error['calls'] ) ) . '</td>';
|
||||
|
||||
if ( ! empty( $component ) ) {
|
||||
echo '<td class="qm-nowrap">' . esc_html( $component->name ) . '</td>';
|
||||
} else {
|
||||
echo '<td><em>' . esc_html__( 'Unknown', 'query-monitor' ) . '</em></td>';
|
||||
}
|
||||
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
|
||||
echo '<tfoot>';
|
||||
echo '<tr>';
|
||||
echo '<td colspan="5">';
|
||||
printf(
|
||||
/* translators: %s: Number of PHP errors */
|
||||
esc_html( _nx( 'Total: %s', 'Total: %s', $count, 'PHP error count', 'query-monitor' ) ),
|
||||
'<span class="qm-items-number">' . esc_html( number_format_i18n( $count ) ) . '</span>'
|
||||
);
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
echo '</tfoot>';
|
||||
|
||||
$this->after_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, string> $class
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function admin_class( array $class ) {
|
||||
/** @var QM_Data_PHP_Errors $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( ! empty( $data->errors ) ) {
|
||||
foreach ( $data->errors as $type => $errors ) {
|
||||
$class[] = 'qm-' . $type;
|
||||
}
|
||||
}
|
||||
|
||||
return $class;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function admin_menu( array $menu ) {
|
||||
/** @var QM_Data_PHP_Errors $data */
|
||||
$data = $this->collector->get_data();
|
||||
$menu_label = array();
|
||||
|
||||
$types = array(
|
||||
/* translators: %s: Number of deprecated PHP errors */
|
||||
'deprecated' => _nx_noop( '%s Deprecated', '%s Deprecated', 'PHP error level', 'query-monitor' ),
|
||||
/* translators: %s: Number of strict PHP errors */
|
||||
'strict' => _nx_noop( '%s Strict', '%s Stricts', 'PHP error level', 'query-monitor' ),
|
||||
/* translators: %s: Number of PHP notices */
|
||||
'notice' => _nx_noop( '%s Notice', '%s Notices', 'PHP error level', 'query-monitor' ),
|
||||
/* translators: %s: Number of PHP warnings */
|
||||
'warning' => _nx_noop( '%s Warning', '%s Warnings', 'PHP error level', 'query-monitor' ),
|
||||
);
|
||||
|
||||
$key = 'quiet';
|
||||
$generic = false;
|
||||
|
||||
foreach ( $types as $type => $label ) {
|
||||
|
||||
$count = 0;
|
||||
$has_errors = false;
|
||||
|
||||
if ( isset( $data->suppressed[ $type ] ) ) {
|
||||
$has_errors = true;
|
||||
$generic = true;
|
||||
}
|
||||
if ( isset( $data->silenced[ $type ] ) ) {
|
||||
$has_errors = true;
|
||||
$generic = true;
|
||||
}
|
||||
if ( isset( $data->errors[ $type ] ) ) {
|
||||
$has_errors = true;
|
||||
$key = $type;
|
||||
$count += (int) array_sum( array_column( $data->errors[ $type ], 'calls' ) );
|
||||
}
|
||||
|
||||
if ( ! $has_errors ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $count ) {
|
||||
$label = sprintf(
|
||||
translate_nooped_plural(
|
||||
$label,
|
||||
$count,
|
||||
'query-monitor'
|
||||
),
|
||||
number_format_i18n( $count )
|
||||
);
|
||||
$menu_label[] = $label;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $menu_label ) && ! $generic ) {
|
||||
return $menu;
|
||||
}
|
||||
|
||||
/* translators: %s: List of PHP error types */
|
||||
$title = __( 'PHP Errors (%s)', 'query-monitor' );
|
||||
|
||||
/* translators: used between list items, there is a space after the comma */
|
||||
$sep = __( ', ', 'query-monitor' );
|
||||
|
||||
if ( count( $menu_label ) ) {
|
||||
$title = sprintf(
|
||||
$title,
|
||||
implode( $sep, array_reverse( $menu_label ) )
|
||||
);
|
||||
} else {
|
||||
$title = __( 'PHP Errors', 'query-monitor' );
|
||||
}
|
||||
|
||||
$menu[ $this->collector->id() ] = $this->menu( array(
|
||||
'id' => "query-monitor-{$key}s",
|
||||
'title' => $title,
|
||||
) );
|
||||
return $menu;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function panel_menu( array $menu ) {
|
||||
if ( ! isset( $menu[ $this->collector->id() ] ) ) {
|
||||
return $menu;
|
||||
}
|
||||
|
||||
/** @var QM_Data_PHP_Errors $data */
|
||||
$data = $this->collector->get_data();
|
||||
$count = 0;
|
||||
$types = array(
|
||||
'suppressed',
|
||||
'silenced',
|
||||
'errors',
|
||||
);
|
||||
|
||||
foreach ( $types as $type ) {
|
||||
if ( ! empty( $data->{$type} ) ) {
|
||||
foreach ( $data->{$type} as $errors ) {
|
||||
$count += array_sum( array_column( $errors, 'calls' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$menu[ $this->collector->id() ]['title'] = esc_html( sprintf(
|
||||
/* translators: %s: Number of errors */
|
||||
__( 'PHP Errors (%s)', 'query-monitor' ),
|
||||
number_format_i18n( $count )
|
||||
) );
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_php_errors( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'php_errors' );
|
||||
if ( $collector ) {
|
||||
$output['php_errors'] = new QM_Output_Html_PHP_Errors( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_php_errors', 110, 2 );
|
252
wp-content/plugins/query-monitor/output/html/request.php
Normal file
252
wp-content/plugins/query-monitor/output/html/request.php
Normal file
@ -0,0 +1,252 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Request data output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Request extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Request Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 50 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Request', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_Request $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
/** @var QM_Collector_DB_Queries|null $db_queries */
|
||||
$db_queries = QM_Collectors::get( 'db_queries' );
|
||||
|
||||
/** @var QM_Collector_Raw_Request|null $raw_request */
|
||||
$raw_request = QM_Collectors::get( 'raw_request' );
|
||||
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
foreach ( array(
|
||||
'request' => __( 'Request', 'query-monitor' ),
|
||||
'matched_rule' => __( 'Matched Rule', 'query-monitor' ),
|
||||
'matched_query' => __( 'Matched Query', 'query-monitor' ),
|
||||
'query_string' => __( 'Query String', 'query-monitor' ),
|
||||
) as $item => $name ) {
|
||||
if ( is_admin() && ! isset( $data->request[ $item ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! empty( $data->request[ $item ] ) ) {
|
||||
if ( in_array( $item, array( 'request', 'matched_query', 'query_string' ), true ) ) {
|
||||
$value = self::format_url( $data->request[ $item ] );
|
||||
} else {
|
||||
$value = esc_html( $data->request[ $item ] );
|
||||
}
|
||||
} else {
|
||||
$value = '<em>' . esc_html__( 'none', 'query-monitor' ) . '</em>';
|
||||
}
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html( $name ) . '</h3>';
|
||||
echo '<p class="qm-ltr"><code>' . $value . '</code></p>'; // WPCS: XSS ok.
|
||||
echo '</section>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
|
||||
echo '<div class="qm-boxed">';
|
||||
|
||||
if ( ! empty( $data->matching_rewrites ) ) {
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'All Matching Rewrite Rules', 'query-monitor' ) . '</h3>';
|
||||
echo '<table>';
|
||||
|
||||
foreach ( $data->matching_rewrites as $rule => $query ) {
|
||||
$query = str_replace( 'index.php?', '', $query );
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td class="qm-ltr"><code>' . esc_html( $rule ) . '</code></td>';
|
||||
echo '<td class="qm-ltr"><code>';
|
||||
echo self::format_url( $query ); // WPCS: XSS ok.
|
||||
echo '</code></td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
echo '</table>';
|
||||
echo '</section>';
|
||||
}
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3>';
|
||||
esc_html_e( 'Query Vars', 'query-monitor' );
|
||||
echo '</h3>';
|
||||
|
||||
if ( $db_queries ) {
|
||||
$db_queries_data = $db_queries->get_data();
|
||||
if ( ! empty( $db_queries_data->wpdb->has_main_query ) ) {
|
||||
echo '<p>';
|
||||
echo self::build_filter_trigger( 'db_queries', 'caller', 'qm-main-query', esc_html__( 'View Main Query', 'query-monitor' ) ); // WPCS: XSS ok;
|
||||
echo '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $data->qvars ) ) {
|
||||
|
||||
echo '<table>';
|
||||
|
||||
foreach ( $data->qvars as $var => $value ) {
|
||||
|
||||
echo '<tr>';
|
||||
|
||||
if ( isset( $data->plugin_qvars[ $var ] ) ) {
|
||||
echo '<th scope="row" class="qm-ltr"><span class="qm-current">' . esc_html( $var ) . '</span></td>';
|
||||
} else {
|
||||
echo '<th scope="row" class="qm-ltr">' . esc_html( $var ) . '</td>';
|
||||
}
|
||||
|
||||
if ( is_array( $value ) || is_object( $value ) ) {
|
||||
echo '<td class="qm-ltr"><pre>';
|
||||
echo esc_html( print_r( $value, true ) );
|
||||
echo '</pre></td>';
|
||||
} else {
|
||||
echo '<td class="qm-ltr qm-wrap">' . esc_html( $value ) . '</td>';
|
||||
}
|
||||
|
||||
echo '</tr>';
|
||||
|
||||
}
|
||||
echo '</table>';
|
||||
|
||||
} else {
|
||||
|
||||
echo '<p><em>' . esc_html__( 'none', 'query-monitor' ) . '</em></p>';
|
||||
|
||||
}
|
||||
|
||||
echo '</section>';
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'Response', 'query-monitor' ) . '</h3>';
|
||||
echo '<h4>' . esc_html__( 'Queried Object', 'query-monitor' ) . '</h4>';
|
||||
|
||||
if ( ! empty( $data->queried_object ) ) {
|
||||
$class = get_class( $data->queried_object['data'] );
|
||||
$class = $class ?: __( 'Unknown', 'query-monitor' );
|
||||
printf(
|
||||
'<p>%1$s (%2$s)</p>',
|
||||
esc_html( $data->queried_object['title'] ),
|
||||
esc_html( $class )
|
||||
);
|
||||
} else {
|
||||
echo '<p><em>' . esc_html__( 'none', 'query-monitor' ) . '</em></p>';
|
||||
}
|
||||
|
||||
echo '<h4>' . esc_html__( 'Current User', 'query-monitor' ) . '</h4>';
|
||||
|
||||
if ( ! empty( $data->user['data'] ) ) {
|
||||
printf( // WPCS: XSS ok.
|
||||
'<p>%s</p>',
|
||||
esc_html( $data->user['title'] )
|
||||
);
|
||||
} else {
|
||||
echo '<p><em>' . esc_html__( 'none', 'query-monitor' ) . '</em></p>';
|
||||
}
|
||||
|
||||
if ( ! empty( $data->multisite ) ) {
|
||||
echo '<h4>' . esc_html__( 'Multisite', 'query-monitor' ) . '</h4>';
|
||||
|
||||
foreach ( $data->multisite as $var => $value ) {
|
||||
printf( // WPCS: XSS ok.
|
||||
'<p>%s</p>',
|
||||
esc_html( $value['title'] )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
echo '</section>';
|
||||
|
||||
if ( ! empty( $raw_request ) ) {
|
||||
/** @var QM_Data_Raw_Request $raw_data */
|
||||
$raw_data = $raw_request->get_data();
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'Request Data', 'query-monitor' ) . '</h3>';
|
||||
echo '<table>';
|
||||
|
||||
foreach ( array(
|
||||
'ip' => __( 'Remote IP', 'query-monitor' ),
|
||||
'method' => __( 'HTTP method', 'query-monitor' ),
|
||||
'url' => __( 'Requested URL', 'query-monitor' ),
|
||||
) as $item => $name ) {
|
||||
echo '<tr>';
|
||||
echo '<th scope="row">' . esc_html( $name ) . '</td>';
|
||||
echo '<td class="qm-ltr qm-wrap">' . esc_html( $raw_data->request[ $item ] ) . '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
echo '</table>';
|
||||
|
||||
echo '</section>';
|
||||
}
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function admin_menu( array $menu ) {
|
||||
/** @var QM_Data_Request $data */
|
||||
$data = $this->collector->get_data();
|
||||
$count = isset( $data->plugin_qvars ) ? count( $data->plugin_qvars ) : 0;
|
||||
|
||||
$title = ( empty( $count ) )
|
||||
? __( 'Request', 'query-monitor' )
|
||||
/* translators: %s: Number of additional query variables */
|
||||
: __( 'Request (+%s)', 'query-monitor' );
|
||||
|
||||
$menu[ $this->collector->id() ] = $this->menu( array(
|
||||
'title' => esc_html( sprintf(
|
||||
$title,
|
||||
number_format_i18n( $count )
|
||||
) ),
|
||||
) );
|
||||
return $menu;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_request( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'request' );
|
||||
if ( $collector ) {
|
||||
$output['request'] = new QM_Output_Html_Request( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_request', 60, 2 );
|
303
wp-content/plugins/query-monitor/output/html/theme.php
Normal file
303
wp-content/plugins/query-monitor/output/html/theme.php
Normal file
@ -0,0 +1,303 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Template and theme output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Theme extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Theme Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 60 );
|
||||
add_filter( 'qm/output/panel_menus', array( $this, 'panel_menu' ), 60 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Theme', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_Theme $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->stylesheet ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'Theme', 'query-monitor' ) . '</h3>';
|
||||
echo '<p>' . esc_html( $data->stylesheet ) . '</p>';
|
||||
|
||||
if ( self::has_clickable_links() ) {
|
||||
echo '<p>';
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo self::output_filename( 'style.css', sprintf( '%s/style.css', $data->theme_dirs[ $data->stylesheet ] ), 0, true );
|
||||
echo '</p>';
|
||||
|
||||
if ( $data->stylesheet_theme_json ) {
|
||||
echo '<p>';
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo self::output_filename( 'theme.json', $data->stylesheet_theme_json, 0, true );
|
||||
echo '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
if ( $data->is_child_theme ) {
|
||||
echo '<h3>' . esc_html__( 'Parent Theme', 'query-monitor' ) . '</h3>';
|
||||
echo '<p>' . esc_html( $data->template ) . '</p>';
|
||||
|
||||
if ( self::has_clickable_links() ) {
|
||||
echo '<p>';
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo self::output_filename( 'style.css', sprintf( '%s/style.css', $data->theme_dirs[ $data->template ] ), 0, true );
|
||||
echo '</p>';
|
||||
|
||||
if ( $data->template_theme_json ) {
|
||||
echo '<p>';
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo self::output_filename( 'theme.json', $data->template_theme_json, 0, true );
|
||||
echo '</p>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo '</section>';
|
||||
|
||||
echo '<section>';
|
||||
if ( ! empty( $data->block_template ) ) {
|
||||
echo '<h3>' . esc_html__( 'Block Template', 'query-monitor' ) . '</h3>';
|
||||
|
||||
if ( $data->block_template->wp_id ) {
|
||||
echo '<p>';
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo self::build_link(
|
||||
QM_Util::get_site_editor_url( $data->block_template->id, 'wp_template' ),
|
||||
esc_html( $data->block_template->id )
|
||||
);
|
||||
echo '</p>';
|
||||
} else {
|
||||
if ( self::has_clickable_links() ) {
|
||||
$file = sprintf(
|
||||
'%s/%s/%s.html',
|
||||
$data->theme_dirs[ $data->block_template->theme ],
|
||||
$data->theme_folders[ $data->block_template->type ],
|
||||
$data->block_template->slug
|
||||
);
|
||||
} else {
|
||||
$file = '';
|
||||
}
|
||||
|
||||
echo '<p class="qm-ltr">' . self::output_filename( sprintf(
|
||||
'%s/%s.html',
|
||||
$data->theme_folders[ $data->block_template->type ],
|
||||
$data->block_template->slug
|
||||
), $file, 0, true ) . '</p>'; // WPCS: XSS ok.
|
||||
}
|
||||
} else {
|
||||
echo '<h3>' . esc_html__( 'Template File', 'query-monitor' ) . '</h3>';
|
||||
|
||||
if ( ! empty( $data->template_path ) ) {
|
||||
if ( $data->is_child_theme ) {
|
||||
$display = $data->theme_template_file;
|
||||
} else {
|
||||
$display = $data->template_file;
|
||||
}
|
||||
if ( self::has_clickable_links() ) {
|
||||
$file = $data->template_path;
|
||||
} else {
|
||||
$file = '';
|
||||
}
|
||||
echo '<p class="qm-ltr">' . self::output_filename( $display, $file, 0, true ) . '</p>'; // WPCS: XSS ok.
|
||||
} else {
|
||||
echo '<p><em>' . esc_html__( 'Unknown', 'query-monitor' ) . '</em></p>';
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $data->template_hierarchy ) ) {
|
||||
echo '<h3>' . esc_html__( 'Template Hierarchy', 'query-monitor' ) . '</h3>';
|
||||
echo '<ol class="qm-ltr"><li>' . implode( '</li><li>', array_map( 'esc_html', $data->template_hierarchy ) ) . '</li></ol>';
|
||||
}
|
||||
|
||||
echo '</section>';
|
||||
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'Template Parts', 'query-monitor' ) . '</h3>';
|
||||
|
||||
if ( ! empty( $data->template_parts ) ) {
|
||||
|
||||
if ( $data->is_child_theme ) {
|
||||
$parts = $data->theme_template_parts;
|
||||
} else {
|
||||
$parts = $data->template_parts;
|
||||
}
|
||||
|
||||
echo '<ul class="qm-ltr">';
|
||||
|
||||
foreach ( $parts as $filename => $display ) {
|
||||
echo '<li>';
|
||||
|
||||
if ( is_int( $filename ) ) {
|
||||
echo self::build_link( QM_Util::get_site_editor_url( $display ), esc_html( $display ) ); // WPCS: XSS ok.
|
||||
} elseif ( self::has_clickable_links() ) {
|
||||
echo self::output_filename( $display, $filename, 0, true ); // WPCS: XSS ok.
|
||||
} else {
|
||||
echo esc_html( $display );
|
||||
}
|
||||
|
||||
if ( $data->count_template_parts[ $filename ] > 1 ) {
|
||||
$count = sprintf(
|
||||
/* translators: %s: The number of times that a template part file was included in the page */
|
||||
_nx( 'Included %s time', 'Included %s times', $data->count_template_parts[ $filename ], 'template parts', 'query-monitor' ),
|
||||
esc_html( number_format_i18n( $data->count_template_parts[ $filename ] ) )
|
||||
);
|
||||
echo '<br><span class="qm-info qm-supplemental">' . esc_html( $count ) . '</span>';
|
||||
}
|
||||
echo '</li>';
|
||||
}
|
||||
|
||||
echo '</ul>';
|
||||
|
||||
} else {
|
||||
echo '<p><em>' . esc_html__( 'None', 'query-monitor' ) . '</em></p>';
|
||||
}
|
||||
|
||||
if ( ! empty( $data->unsuccessful_template_parts ) ) {
|
||||
echo '<h4>' . esc_html__( 'Not Loaded', 'query-monitor' ) . '</h4>';
|
||||
echo '<ul>';
|
||||
|
||||
foreach ( $data->unsuccessful_template_parts as $requested ) {
|
||||
if ( $requested['name'] ) {
|
||||
echo '<li>';
|
||||
$text = $requested['slug'] . '-' . $requested['name'] . '.php';
|
||||
echo self::output_filename( $text, $requested['caller']['file'], $requested['caller']['line'], true ); // WPCS: XSS ok.
|
||||
echo '</li>';
|
||||
}
|
||||
|
||||
echo '<li>';
|
||||
$text = $requested['slug'] . '.php';
|
||||
echo self::output_filename( $text, $requested['caller']['file'], $requested['caller']['line'], true ); // WPCS: XSS ok.
|
||||
echo '</li>';
|
||||
}
|
||||
|
||||
echo '</ul>';
|
||||
}
|
||||
|
||||
echo '</section>';
|
||||
|
||||
if ( ! empty( $data->timber_files ) ) {
|
||||
echo '<section>';
|
||||
echo '<h3>' . esc_html__( 'Twig Template Files', 'query-monitor' ) . '</h3>';
|
||||
echo '<ul class="qm-ltr">';
|
||||
|
||||
foreach ( $data->timber_files as $filename ) {
|
||||
echo '<li>' . esc_html( $filename ) . '</li>';
|
||||
}
|
||||
|
||||
echo '</ul>';
|
||||
echo '</section>';
|
||||
}
|
||||
|
||||
if ( ! empty( $data->body_class ) ) {
|
||||
echo '<section>';
|
||||
|
||||
echo '<h3>' . esc_html__( 'Body Classes', 'query-monitor' ) . '</h3>';
|
||||
echo '<ul class="qm-ltr">';
|
||||
|
||||
foreach ( $data->body_class as $class ) {
|
||||
echo '<li>' . esc_html( $class ) . '</li>';
|
||||
}
|
||||
|
||||
echo '</ul>';
|
||||
echo '</section>';
|
||||
}
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function admin_menu( array $menu ) {
|
||||
/** @var QM_Data_Theme $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( ! empty( $data->block_template ) ) {
|
||||
if ( $data->block_template->wp_id ) {
|
||||
$name = $data->block_template->id;
|
||||
} else {
|
||||
$name = sprintf(
|
||||
'%s/%s.html',
|
||||
$data->theme_folders[ $data->block_template->type ],
|
||||
$data->block_template->slug
|
||||
);
|
||||
}
|
||||
} elseif ( isset( $data->template_file ) ) {
|
||||
$name = ( $data->is_child_theme ) ? $data->theme_template_file : $data->template_file;
|
||||
} else {
|
||||
$name = __( 'Unknown', 'query-monitor' );
|
||||
}
|
||||
|
||||
$menu[ $this->collector->id() ] = $this->menu( array(
|
||||
'title' => esc_html( sprintf(
|
||||
/* translators: %s: Template file name */
|
||||
__( 'Template: %s', 'query-monitor' ),
|
||||
$name
|
||||
) ),
|
||||
) );
|
||||
|
||||
return $menu;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function panel_menu( array $menu ) {
|
||||
if ( isset( $menu[ $this->collector->id() ] ) ) {
|
||||
$menu[ $this->collector->id() ]['title'] = __( 'Template', 'query-monitor' );
|
||||
}
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_theme( array $output, QM_Collectors $collectors ) {
|
||||
if ( is_admin() ) {
|
||||
return $output;
|
||||
}
|
||||
$collector = QM_Collectors::get( 'response' );
|
||||
if ( $collector ) {
|
||||
$output['response'] = new QM_Output_Html_Theme( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_theme', 70, 2 );
|
244
wp-content/plugins/query-monitor/output/html/timing.php
Normal file
244
wp-content/plugins/query-monitor/output/html/timing.php
Normal file
@ -0,0 +1,244 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Timing and profiling output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Timing extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Timing Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 46 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Timing', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_Timing $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->timing ) && empty( $data->warning ) ) {
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
$notice = sprintf(
|
||||
/* translators: %s: Link to help article */
|
||||
__( 'No data logged. <a href="%s">Read about timing and profiling in Query Monitor</a>.', 'query-monitor' ),
|
||||
'https://querymonitor.com/blog/2018/07/profiling-and-logging/'
|
||||
);
|
||||
echo $this->build_notice( $notice ); // WPCS: XSS ok.
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->before_tabular_output();
|
||||
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col">' . esc_html__( 'Tracked Function', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col" class="qm-num">' . esc_html__( 'Started', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col" class="qm-num">' . esc_html__( 'Stopped', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col" class="qm-num">' . esc_html__( 'Time', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col" class="qm-num">' . esc_html__( 'Memory', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Component', 'query-monitor' ) . '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
|
||||
echo '<tbody>';
|
||||
|
||||
if ( ! empty( $data->timing ) ) {
|
||||
foreach ( $data->timing as $row ) {
|
||||
|
||||
$component = $row['component'];
|
||||
$trace = $row['filtered_trace'];
|
||||
$file = self::output_filename( $row['function'], $trace[0]['file'], $trace[0]['line'] );
|
||||
|
||||
echo '<tr>';
|
||||
|
||||
if ( self::has_clickable_links() ) {
|
||||
echo '<td class="qm-ltr">';
|
||||
echo $file; // WPCS: XSS ok.
|
||||
echo '</td>';
|
||||
} else {
|
||||
echo '<td class="qm-ltr qm-has-toggle">';
|
||||
echo self::build_toggler(); // WPCS: XSS ok;
|
||||
echo '<ol>';
|
||||
echo '<li>';
|
||||
echo $file; // WPCS: XSS ok.
|
||||
echo '</li>';
|
||||
echo '</ol></td>';
|
||||
}
|
||||
|
||||
printf(
|
||||
'<td class="qm-num">%s</td>',
|
||||
esc_html( number_format_i18n( $row['start_time'], 4 ) )
|
||||
);
|
||||
|
||||
printf(
|
||||
'<td class="qm-num">%s</td>',
|
||||
esc_html( number_format_i18n( $row['end_time'], 4 ) )
|
||||
);
|
||||
|
||||
printf(
|
||||
'<td class="qm-num">%s</td>',
|
||||
esc_html( number_format_i18n( $row['function_time'], 4 ) )
|
||||
);
|
||||
|
||||
$mem = sprintf(
|
||||
/* translators: %s: Approximate memory used in kilobytes */
|
||||
__( '~%s kB', 'query-monitor' ),
|
||||
number_format_i18n( $row['function_memory'] / 1024 )
|
||||
);
|
||||
printf(
|
||||
'<td class="qm-num">%s</td>',
|
||||
esc_html( $mem )
|
||||
);
|
||||
printf(
|
||||
'<td class="qm-nowrap">%s</td>',
|
||||
esc_html( $component->name )
|
||||
);
|
||||
|
||||
echo '</tr>';
|
||||
|
||||
if ( ! empty( $row['laps'] ) ) {
|
||||
foreach ( $row['laps'] as $lap_id => $lap ) {
|
||||
echo '<tr>';
|
||||
|
||||
echo '<td class="qm-ltr"><code>— ';
|
||||
echo esc_html( $row['function'] . ': ' . $lap_id );
|
||||
echo '</code></td>';
|
||||
|
||||
echo '<td class="qm-num"></td>';
|
||||
echo '<td class="qm-num"></td>';
|
||||
|
||||
printf(
|
||||
'<td class="qm-num">%s</td>',
|
||||
esc_html( number_format_i18n( $lap['time_used'], 4 ) )
|
||||
);
|
||||
|
||||
$mem = sprintf(
|
||||
/* translators: %s: Approximate memory used in kilobytes */
|
||||
__( '~%s kB', 'query-monitor' ),
|
||||
number_format_i18n( $lap['memory_used'] / 1024 )
|
||||
);
|
||||
printf(
|
||||
'<td class="qm-num">%s</td>',
|
||||
esc_html( $mem )
|
||||
);
|
||||
echo '<td class="qm-nowrap"></td>';
|
||||
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $data->warning ) ) {
|
||||
foreach ( $data->warning as $row ) {
|
||||
$component = $row['component'];
|
||||
$trace = $row['filtered_trace'];
|
||||
$file = self::output_filename( $row['function'], $trace[0]['file'], $trace[0]['line'] );
|
||||
|
||||
echo '<tr class="qm-warn">';
|
||||
if ( self::has_clickable_links() ) {
|
||||
echo '<td class="qm-ltr">';
|
||||
echo $file; // WPCS: XSS ok.
|
||||
echo '</td>';
|
||||
} else {
|
||||
echo '<td class="qm-ltr qm-has-toggle">';
|
||||
echo self::build_toggler(); // WPCS: XSS ok;
|
||||
echo '<ol>';
|
||||
echo '<li>';
|
||||
echo $file; // WPCS: XSS ok.
|
||||
echo '</li>';
|
||||
echo '</ol></td>';
|
||||
}
|
||||
|
||||
printf(
|
||||
'<td colspan="4">%1$s%2$s</td>',
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
QueryMonitor::icon( 'warning' ),
|
||||
esc_html( $row['message'] )
|
||||
);
|
||||
|
||||
printf(
|
||||
'<td class="qm-nowrap">%s</td>',
|
||||
esc_html( $component->name )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
echo '</tbody>';
|
||||
|
||||
$this->after_tabular_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function admin_menu( array $menu ) {
|
||||
/** @var QM_Data_Timing $data */
|
||||
$data = $this->collector->get_data();
|
||||
$count = 0;
|
||||
|
||||
if ( ! empty( $data->timing ) || ! empty( $data->warning ) ) {
|
||||
if ( ! empty( $data->timing ) ) {
|
||||
$count += count( $data->timing );
|
||||
}
|
||||
if ( ! empty( $data->warning ) ) {
|
||||
$count += count( $data->warning );
|
||||
}
|
||||
/* translators: %s: Number of function timing results that are available */
|
||||
$label = __( 'Timings (%s)', 'query-monitor' );
|
||||
} else {
|
||||
$label = __( 'Timings', 'query-monitor' );
|
||||
}
|
||||
|
||||
$menu[ $this->collector->id() ] = $this->menu( array(
|
||||
'title' => esc_html( sprintf(
|
||||
$label,
|
||||
number_format_i18n( $count )
|
||||
) ),
|
||||
) );
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_timing( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'timing' );
|
||||
if ( $collector ) {
|
||||
$output['timing'] = new QM_Output_Html_Timing( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_timing', 15, 2 );
|
175
wp-content/plugins/query-monitor/output/html/transients.php
Normal file
175
wp-content/plugins/query-monitor/output/html/transients.php
Normal file
@ -0,0 +1,175 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Transient storage output for HTML pages.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class QM_Output_Html_Transients extends QM_Output_Html {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Transients Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
public function __construct( QM_Collector $collector ) {
|
||||
parent::__construct( $collector );
|
||||
add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 100 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Transients', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function output() {
|
||||
/** @var QM_Data_Transients $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( ! empty( $data->trans ) ) {
|
||||
|
||||
$this->before_tabular_output();
|
||||
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th scope="col">' . esc_html__( 'Updated Transient', 'query-monitor' ) . '</th>';
|
||||
if ( $data->has_type ) {
|
||||
echo '<th scope="col">' . esc_html_x( 'Type', 'transient type', 'query-monitor' ) . '</th>';
|
||||
}
|
||||
echo '<th scope="col">' . esc_html__( 'Expiration', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html_x( 'Size', 'size of transient value', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Caller', 'query-monitor' ) . '</th>';
|
||||
echo '<th scope="col">' . esc_html__( 'Component', 'query-monitor' ) . '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
|
||||
echo '<tbody>';
|
||||
|
||||
foreach ( $data->trans as $row ) {
|
||||
$component = $row['component'];
|
||||
|
||||
echo '<tr>';
|
||||
printf(
|
||||
'<td class="qm-ltr"><code>%s</code></td>',
|
||||
esc_html( $row['name'] )
|
||||
);
|
||||
if ( $data->has_type ) {
|
||||
printf(
|
||||
'<td class="qm-ltr qm-nowrap">%s</td>',
|
||||
esc_html( $row['type'] )
|
||||
);
|
||||
}
|
||||
|
||||
if ( 0 === $row['expiration'] ) {
|
||||
printf(
|
||||
'<td class="qm-nowrap"><em>%s</em></td>',
|
||||
esc_html__( 'none', 'query-monitor' )
|
||||
);
|
||||
} else {
|
||||
printf(
|
||||
'<td class="qm-nowrap">%s <span class="qm-info">(~%s)</span></td>',
|
||||
esc_html( (string) $row['expiration'] ),
|
||||
esc_html( $row['exp_diff'] )
|
||||
);
|
||||
}
|
||||
|
||||
printf(
|
||||
'<td class="qm-nowrap">~%s</td>',
|
||||
esc_html( $row['size_formatted'] )
|
||||
);
|
||||
|
||||
$stack = array();
|
||||
|
||||
foreach ( $row['filtered_trace'] as $frame ) {
|
||||
$stack[] = self::output_filename( $frame['display'], $frame['calling_file'], $frame['calling_line'] );
|
||||
}
|
||||
|
||||
$caller = array_shift( $stack );
|
||||
|
||||
echo '<td class="qm-has-toggle qm-nowrap qm-ltr">';
|
||||
|
||||
if ( ! empty( $stack ) ) {
|
||||
echo self::build_toggler(); // WPCS: XSS ok;
|
||||
}
|
||||
|
||||
echo '<ol>';
|
||||
|
||||
echo "<li>{$caller}</li>"; // WPCS: XSS ok.
|
||||
|
||||
if ( ! empty( $stack ) ) {
|
||||
echo '<div class="qm-toggled"><li>' . implode( '</li><li>', $stack ) . '</li></div>'; // WPCS: XSS ok.
|
||||
}
|
||||
|
||||
echo '</ol></td>';
|
||||
|
||||
printf(
|
||||
'<td class="qm-nowrap">%s</td>',
|
||||
esc_html( $component->name )
|
||||
);
|
||||
|
||||
echo '</tr>';
|
||||
|
||||
}
|
||||
|
||||
$this->after_tabular_output();
|
||||
} else {
|
||||
$this->before_non_tabular_output();
|
||||
|
||||
$notice = __( 'No transients set.', 'query-monitor' );
|
||||
echo $this->build_notice( $notice ); // WPCS: XSS ok.
|
||||
|
||||
$this->after_non_tabular_output();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed[]> $menu
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function admin_menu( array $menu ) {
|
||||
/** @var QM_Data_Transients $data */
|
||||
$data = $this->collector->get_data();
|
||||
$count = count( $data->trans );
|
||||
|
||||
$title = ( empty( $count ) )
|
||||
? __( 'Transient Updates', 'query-monitor' )
|
||||
/* translators: %s: Number of transient values that were updated */
|
||||
: __( 'Transient Updates (%s)', 'query-monitor' );
|
||||
|
||||
$menu[ $this->collector->id() ] = $this->menu( array(
|
||||
'title' => esc_html( sprintf(
|
||||
$title,
|
||||
number_format_i18n( $count )
|
||||
) ),
|
||||
) );
|
||||
return $menu;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_html_transients( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'transients' );
|
||||
if ( $collector ) {
|
||||
$output['transients'] = new QM_Output_Html_Transients( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/html', 'register_qm_output_html_transients', 100, 2 );
|
60
wp-content/plugins/query-monitor/output/raw/cache.php
Normal file
60
wp-content/plugins/query-monitor/output/raw/cache.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Raw cache output.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
class QM_Output_Raw_Cache extends QM_Output_Raw {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Cache Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Object Cache', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function get_output() {
|
||||
$output = array(
|
||||
'hit_percentage' => null,
|
||||
'hits' => null,
|
||||
'misses' => null,
|
||||
);
|
||||
|
||||
/** @var QM_Data_Cache $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( ! empty( $data->stats ) && ! empty( $data->cache_hit_percentage ) ) {
|
||||
$output['hit_percentage'] = round( $data->cache_hit_percentage, 1 );
|
||||
$output['hits'] = (int) $data->stats['cache_hits'];
|
||||
$output['misses'] = (int) $data->stats['cache_misses'];
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_raw_cache( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'cache' );
|
||||
if ( $collector ) {
|
||||
$output['cache'] = new QM_Output_Raw_Cache( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/raw', 'register_qm_output_raw_cache', 30, 2 );
|
47
wp-content/plugins/query-monitor/output/raw/conditionals.php
Normal file
47
wp-content/plugins/query-monitor/output/raw/conditionals.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Raw conditionals output.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
class QM_Output_Raw_Conditionals extends QM_Output_Raw {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Conditionals Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Conditionals', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_output() {
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
return $data->conds['true'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_raw_conditionals( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'conditionals' );
|
||||
if ( $collector ) {
|
||||
$output['conditionals'] = new QM_Output_Raw_Conditionals( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/raw', 'register_qm_output_raw_conditionals', 20, 2 );
|
139
wp-content/plugins/query-monitor/output/raw/db_queries.php
Normal file
139
wp-content/plugins/query-monitor/output/raw/db_queries.php
Normal file
@ -0,0 +1,139 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Raw database query output.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
class QM_Output_Raw_DB_Queries extends QM_Output_Raw {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_DB_Queries Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $query_row = 0;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Database Queries', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function get_output() {
|
||||
$output = array();
|
||||
/** @var QM_Data_DB_Queries $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->wpdb ) ) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
$output['wpdb'] = $this->output_queries( $data->wpdb );
|
||||
|
||||
if ( ! empty( $data->errors ) ) {
|
||||
$output['errors'] = array(
|
||||
'total' => count( $data->errors ),
|
||||
'errors' => $data->errors,
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $data->dupes ) ) {
|
||||
$dupes = $data->dupes;
|
||||
|
||||
// Filter out SQL queries that do not have dupes
|
||||
$dupes = array_filter( $dupes, array( $this->collector, 'filter_dupe_items' ) );
|
||||
|
||||
// Ignore dupes from `WP_Query->set_found_posts()`
|
||||
unset( $dupes['SELECT FOUND_ROWS()'] );
|
||||
|
||||
$output['dupes'] = array(
|
||||
'total' => count( $dupes ),
|
||||
'queries' => $dupes,
|
||||
);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stdClass $db
|
||||
* @return array
|
||||
* @phpstan-return array{
|
||||
* total: int,
|
||||
* time: float,
|
||||
* queries: mixed[],
|
||||
* }|array{}
|
||||
*/
|
||||
protected function output_queries( stdClass $db ) {
|
||||
$this->query_row = 0;
|
||||
|
||||
$output = array();
|
||||
|
||||
if ( empty( $db->rows ) ) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
foreach ( $db->rows as $row ) {
|
||||
$output[] = $this->output_query_row( $row );
|
||||
}
|
||||
|
||||
return array(
|
||||
'total' => $db->total_qs,
|
||||
'time' => round( $db->total_time, 4 ),
|
||||
'queries' => $output,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $row
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
protected function output_query_row( array $row ) {
|
||||
$output = array();
|
||||
|
||||
$output['i'] = ++$this->query_row;
|
||||
$output['sql'] = $row['sql'];
|
||||
$output['time'] = round( $row['ltime'], 4 );
|
||||
|
||||
if ( isset( $row['trace'] ) ) {
|
||||
$stack = array();
|
||||
$filtered_trace = $row['trace']->get_filtered_trace();
|
||||
|
||||
foreach ( $filtered_trace as $item ) {
|
||||
$stack[] = $item['display'];
|
||||
}
|
||||
} else {
|
||||
$stack = $row['stack'];
|
||||
}
|
||||
|
||||
$output['stack'] = $stack;
|
||||
$output['result'] = $row['result'];
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_raw_db_queries( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'db_queries' );
|
||||
if ( $collector ) {
|
||||
$output['db_queries'] = new QM_Output_Raw_DB_Queries( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/raw', 'register_qm_output_raw_db_queries', 20, 2 );
|
75
wp-content/plugins/query-monitor/output/raw/http.php
Normal file
75
wp-content/plugins/query-monitor/output/raw/http.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Raw HTTP API request output.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
class QM_Output_Raw_HTTP extends QM_Output_Raw {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_HTTP Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'HTTP API Calls', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function get_output() {
|
||||
$output = array();
|
||||
/** @var QM_Data_HTTP $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->http ) ) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
$requests = array();
|
||||
|
||||
foreach ( $data->http as $http ) {
|
||||
$stack = array();
|
||||
|
||||
foreach ( $http['filtered_trace'] as $item ) {
|
||||
$stack[] = $item['display'];
|
||||
}
|
||||
|
||||
$requests[] = array(
|
||||
'url' => $http['url'],
|
||||
'method' => $http['args']['method'],
|
||||
'response' => ( $http['response'] instanceof WP_Error ) ? $http['response']->get_error_message() : $http['response']['response'],
|
||||
'time' => round( $http['ltime'], 4 ),
|
||||
'stack' => $stack,
|
||||
);
|
||||
}
|
||||
|
||||
$output['total'] = count( $requests );
|
||||
$output['time'] = round( $data->ltime, 4 );
|
||||
$output['requests'] = $requests;
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_raw_http( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'http' );
|
||||
if ( $collector ) {
|
||||
$output['http'] = new QM_Output_Raw_HTTP( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/raw', 'register_qm_output_raw_http', 30, 2 );
|
64
wp-content/plugins/query-monitor/output/raw/logger.php
Normal file
64
wp-content/plugins/query-monitor/output/raw/logger.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Raw logger output.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
class QM_Output_Raw_Logger extends QM_Output_Raw {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Logger Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Logs', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, array<int, array<string, mixed>>>
|
||||
* @phpstan-return array<QM_Collector_Logger::*, list<array{
|
||||
* message: string,
|
||||
* stack: list<string>,
|
||||
* }>>
|
||||
*/
|
||||
public function get_output() {
|
||||
$output = array();
|
||||
/** @var QM_Data_Logger $data */
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->logs ) ) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
foreach ( $data->logs as $log ) {
|
||||
$output[ $log['level'] ][] = array(
|
||||
'message' => $log['message'],
|
||||
'stack' => array_column( $log['filtered_trace'], 'display' ),
|
||||
);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_raw_logger( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'logger' );
|
||||
if ( $collector ) {
|
||||
$output['logger'] = new QM_Output_Raw_Logger( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/raw', 'register_qm_output_raw_logger', 30, 2 );
|
73
wp-content/plugins/query-monitor/output/raw/transients.php
Normal file
73
wp-content/plugins/query-monitor/output/raw/transients.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php declare(strict_types = 1);
|
||||
/**
|
||||
* Raw transients output.
|
||||
*
|
||||
* @package query-monitor
|
||||
*/
|
||||
|
||||
class QM_Output_Raw_Transients extends QM_Output_Raw {
|
||||
|
||||
/**
|
||||
* Collector instance.
|
||||
*
|
||||
* @var QM_Collector_Transients Collector.
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'Transients', 'query-monitor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function get_output() {
|
||||
$output = array();
|
||||
$data = $this->collector->get_data();
|
||||
|
||||
if ( empty( $data->trans ) ) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
$transients = array();
|
||||
|
||||
foreach ( $data->trans as $transient ) {
|
||||
$stack = array();
|
||||
|
||||
foreach ( $transient['filtered_trace'] as $frame ) {
|
||||
$stack[] = $frame['display'];
|
||||
}
|
||||
|
||||
$transients[] = array(
|
||||
'name' => $transient['name'],
|
||||
'type' => $transient['type'],
|
||||
'size' => $transient['size_formatted'],
|
||||
'expiration' => $transient['expiration'],
|
||||
'stack' => $stack,
|
||||
);
|
||||
}
|
||||
|
||||
$output['total'] = count( $transients );
|
||||
$output['transients'] = $transients;
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, QM_Output> $output
|
||||
* @param QM_Collectors $collectors
|
||||
* @return array<string, QM_Output>
|
||||
*/
|
||||
function register_qm_output_raw_transients( array $output, QM_Collectors $collectors ) {
|
||||
$collector = QM_Collectors::get( 'transients' );
|
||||
if ( $collector ) {
|
||||
$output['transients'] = new QM_Output_Raw_Transients( $collector );
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
add_filter( 'qm/outputter/raw', 'register_qm_output_raw_transients', 30, 2 );
|
Reference in New Issue
Block a user