Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions assets/web-vitals.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 40 additions & 0 deletions collectors/web-vitals.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php declare(strict_types = 1);
/**
* Web vitals dummy collector.
*
* @package query-monitor
*/

if ( ! defined( 'ABSPATH' ) ) {
exit;
}

/**
* @extends QM_DataCollector<QM_Data_Web_Vitals>
*/
class QM_Collector_Web_Vitals extends QM_DataCollector {

/**
* @var string
*/
public $id = 'web-vitals';

/**
* @var bool
*/
protected static $hide_core;

public function get_storage(): QM_Data {
return new QM_Data_Web_Vitals();
}

/**
* @return void
*/
public function process() {

}

}

QM_Collectors::add( new QM_Collector_Web_Vitals() );
28 changes: 28 additions & 0 deletions data/web_vitals.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php declare(strict_types = 1);
/**
* Web_Vitals data transfer object.
*
* @package query-monitor
*/

class QM_Data_Web_Vitals extends QM_Data {
/**
* Not used, data is generated for each load and not stored.
*/
public $web_vitals;

/**
* @var array<int, string>
*/
public $parts;

/**
* @var array<string, string>
*/
public $components;

/**
* @var bool
*/
public $all_web_vitals;
}
12 changes: 12 additions & 0 deletions dispatchers/Html.php
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,18 @@ public function enqueue_assets() {
$deps = array();
}

// Measure Web Vitals with the web-vitals.js script. See https://github.com/GoogleChrome/web-vitals.
// Only load if the wp-admin bar is visible.
if ( is_admin_bar_showing() ) {
wp_enqueue_script(
'qm-web-vitals',
$this->qm->plugin_url( 'assets/web-vitals.js' ),
array(),
'3.3.2',
true
);
}

wp_enqueue_style(
'query-monitor',
$this->qm->plugin_url( 'assets/query-monitor.css' ),
Expand Down
106 changes: 106 additions & 0 deletions output/html/web_vitals.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php declare(strict_types = 1);
/**
* Web Vitals for HTML pages.
*
* @package query-monitor
*/

if ( ! defined( 'ABSPATH' ) ) {
exit;
}

class QM_Output_Web_Vitals 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() {
return __( 'Web Vitals', 'query-monitor' );
}

/**
* @return void
*/
public function output() {
if ( ! wp_script_is( 'qm-web-vitals', 'enqueued' ) && ! wp_script_is( 'qm-web-vitals', 'done' ) ) {
$this->before_non_tabular_output();
/* translators: %s: Script handle. */
$notice = sprintf( __( 'Script %s is not available.', 'query-monitor' ), 'qm-web-vitals' );
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__( 'Metric', 'query-monitor' ) . '</th>';
echo '<th scope="col">' . esc_html__( 'Score', 'query-monitor' ) . '</th>';
echo '<th scope="col">' . esc_html__( 'Rating', 'query-monitor' ) . '</th>';
echo '<th scope="col">' . esc_html__( 'Details', 'query-monitor' ) . '</th>';
echo '</th>';
echo '</tr>';
echo '</thead>';

echo '<tbody id="qm-web-vitals-inner">';
echo '<tr class="waiting">';
echo '<td colspan="4">';
echo '<div class="qm-none"><p>Waiting for data...</p></div>';
echo '</td>';
echo '</tr>';
echo '</tbody>';

$this->after_tabular_output();
echo '<script>
// Insert the web vital into the qm-web-vitals div.
function insertWebVital( webVital ) {
var webVitalsDiv = document.getElementById( "qm-web-vitals-inner" );
var divToAdd = document.createElement("tr");
divToAdd.innerHTML = "<td>" + webVital.name + "</td>" +
"<td>" + webVital.value + "</td>" +
"<td>" + webVital.rating + "</td>" +
"<td><pre class=\"qm-pre-wrap\"><code>" + JSON.stringify( webVital ) + "</code></pre></td>";
webVitalsDiv.querySelector( ".waiting" )?.remove();
webVitalsDiv.appendChild( divToAdd );
}

// Collect and display the available metrics.
webVitals.onFCP( insertWebVital ); // Available at load
webVitals.onTTFB( insertWebVital ); // Available at load
webVitals.onFID( insertWebVital ); // Available after interaction
webVitals.onLCP( insertWebVital ); // Available after interaction
webVitals.onCLS( insertWebVital ); // Only available on unload.
webVitals.onINP( insertWebVital ); // Only available on unload.
</script>';
}


}

/**
* @param array<string, QM_Output> $output
* @param QM_Collectors $collectors
* @return array<string, QM_Output>
*/
function register_qm_output_web_vitals( array $output, QM_Collectors $collectors ) {
$collector = QM_Collectors::get( 'web-vitals' );
if ( $collector ) {
$output['web-vitals'] = new QM_Output_Web_Vitals( $collector );
}
return $output;
}

add_filter( 'qm/outputter/html', 'register_qm_output_web_vitals', 80, 2 );