Step-by-Step Guide to building a custom automated performance diagnostic log block for Gutenberg using HTMX dynamic attributes
Gutenberg Block Structure and Initialization
We’ll begin by defining the fundamental structure of our Gutenberg block. This involves registering the block type in PHP and setting up its JavaScript components. The block will be designed to accept a URL as input, which will then be used to trigger an asynchronous performance diagnostic.
PHP Block Registration
The core registration logic resides in your plugin’s main PHP file or a dedicated block registration file. This ensures the block is recognized by WordPress.
<?php
/**
* Plugin Name: Custom Performance Diagnostic Block
* Description: Adds a Gutenberg block for automated performance diagnostics.
* Version: 1.0.0
* Author: Antigravity
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Register the custom block.
*/
function antigravity_performance_diagnostic_block_register() {
// Automatically load dependencies and version.
$asset_file = include( plugin_dir_path( __FILE__ ) . 'build/index.asset.php');
register_block_type( __DIR__, array(
'editor_script' => 'antigravity-performance-diagnostic-block-editor-script',
'editor_style' => 'antigravity-performance-diagnostic-block-editor-style',
'style' => 'antigravity-performance-diagnostic-block-style',
'script' => 'antigravity-performance-diagnostic-block-script',
'dependencies' => $asset_file['dependencies'],
'version' => $asset_file['version'],
) );
}
add_action( 'init', 'antigravity_performance_diagnostic_block_register' );
/**
* Enqueue block assets.
*/
function antigravity_performance_diagnostic_block_enqueue_assets() {
wp_enqueue_script(
'antigravity-performance-diagnostic-block-script',
plugin_dir_url( __FILE__ ) . 'build/index.js',
array( 'wp-element', 'wp-blocks', 'wp-components', 'wp-i18n', 'wp-editor', 'htmx' ), // Ensure htmx is enqueued
filemtime( plugin_dir_path( __FILE__ ) . 'build/index.js' )
);
// Localize script for AJAX URL
wp_localize_script( 'antigravity-performance-diagnostic-block-script', 'antigravity_performance_diagnostic_block_ajax_object', array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'antigravity_performance_diagnostic_block_nonce' ),
) );
}
add_action( 'wp_enqueue_scripts', 'antigravity_performance_diagnostic_block_enqueue_assets' );
// Ensure HTMX is loaded. You might enqueue it here if not already present.
// For demonstration, assuming HTMX is available globally or enqueued by another plugin/theme.
// If not, add:
// wp_enqueue_script( 'htmx', 'https://unpkg.com/[email protected]', array(), '1.9.10', true );
JavaScript Block Registration and Editor Interface
The JavaScript side defines the block’s appearance and behavior within the Gutenberg editor. We’ll use the `registerBlockType` function from `@wordpress/blocks`.
// src/index.js
import { registerBlockType } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import { TextControl, Button, PanelBody } from '@wordpress/components';
import { InspectorControls } from '@wordpress/block-editor';
import './style.scss'; // For frontend styles
import './editor.scss'; // For editor styles
const Edit = ( { attributes, setAttributes } ) => {
const { targetUrl } = attributes;
const onChangeTargetUrl = ( newUrl ) => {
setAttributes( { targetUrl: newUrl } );
};
return (
<>
<InspectorControls>
<PanelBody title={ __( 'Performance Settings', 'antigravity-performance-diagnostic-block' ) }>
<TextControl
label={ __( 'Target URL', 'antigravity-performance-diagnostic-block' ) }
value={ targetUrl }
onChange={ onChangeTargetUrl }
help={ __( 'Enter the URL to diagnose.', 'antigravity-performance-diagnostic-block' ) }
/>
</PanelBody>
</InspectorControls>
<div className="antigravity-performance-diagnostic-block-editor">
<p>{ __( 'Performance Diagnostic Block', 'antigravity-performance-diagnostic-block' ) }</p>
{ targetUrl ? (
<p>{ __( 'Target URL: ', 'antigravity-performance-diagnostic-block' ) }{ targetUrl }</p>
) : (
<p>{ __( 'Configure a Target URL in the block settings.', 'antigravity-performance-diagnostic-block' ) }</p>
) }
</div>
</>
);
};
const Save = ( { attributes } ) => {
const { targetUrl } = attributes;
if ( ! targetUrl ) {
return null; // Don't render anything if no URL is set
}
// HTMX attributes for dynamic loading and swapping
const htmxAttributes = {
'hx-get': `/wp-admin/admin-ajax.php?action=antigravity_diagnose_performance&url=${ encodeURIComponent( targetUrl ) }&_ajax_nonce=${ antigravity_performance_diagnostic_block_ajax_object.nonce }`,
'hx-trigger': 'load', // Trigger on page load
'hx-swap': 'innerHTML', // Replace the content of this element
'hx-target': '.antigravity-performance-diagnostic-block-output', // Target a specific element for output
};
return (
<div className="antigravity-performance-diagnostic-block-frontend">
<p>{ __( 'Performance Diagnostic for: ', 'antigravity-performance-diagnostic-block' ) }{ targetUrl }</p>
<div className="antigravity-performance-diagnostic-block-output" { ...htmxAttributes }>
{ __( 'Loading performance data...', 'antigravity-performance-diagnostic-block' ) }
</div>
</div>
);
};
registerBlockType( 'antigravity/performance-diagnostic', {
title: __( 'Performance Diagnostic', 'antigravity-performance-diagnostic-block' ),
icon: 'performance', // WordPress Dashicon
category: 'widgets',
attributes: {
targetUrl: {
type: 'string',
default: '',
},
},
edit: Edit,
save: Save,
} );
AJAX Handler for Performance Diagnostics
This PHP function will handle the AJAX request, perform the diagnostic, and return the results. For this example, we’ll simulate a diagnostic by fetching basic HTTP headers and response time. In a production environment, you would integrate with tools like GTmetrix, WebPageTest, or use PHP libraries for more in-depth analysis (e.g., cURL for timing, DOM parsing for content analysis).
'URL parameter is missing.' ), 400 );
}
$url = sanitize_url( $_GET['url'] );
// Basic validation to ensure it's a valid URL format
if ( ! filter_var( $url, FILTER_VALIDATE_URL ) ) {
wp_send_json_error( array( 'message' => 'Invalid URL format.' ), 400 );
}
// --- Performance Diagnostic Logic ---
$start_time = microtime( true );
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_HEADER, true ); // Get headers
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true ); // Follow redirects
curl_setopt( $ch, CURLOPT_TIMEOUT, 10 ); // Timeout in seconds
curl_setopt( $ch, CURLOPT_USERAGENT, 'AntigravityPerformanceBot/1.0' ); // Set a user agent
$response = curl_exec( $ch );
$http_code = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
$curl_error = curl_error( $ch );
$end_time = microtime( true );
curl_close( $ch );
$response_time = ( $end_time - $start_time ) * 1000; // in milliseconds
if ( $curl_error ) {
wp_send_json_error( array( 'message' => 'cURL Error: ' . $curl_error ), 500 );
}
// Parse headers
list( $headers, $body ) = explode( "\r\n\r\n", $response, 2 );
$headers_array = preg_split( '/\r\n|\\r|\\n/', $headers );
// --- Format Output for HTMX ---
// This output will be directly inserted into the DOM by HTMX.
echo '<h4>Diagnostic Results for: ' . esc_html( $url ) . '</h4>';
echo '<p><strong>HTTP Status Code:</strong> ' . esc_html( $http_code ) . '</p>';
echo '<p><strong>Response Time:</strong> ' . esc_html( round( $response_time, 2 ) ) . ' ms</p>';
echo '<h5>Response Headers:</h5>';
echo '<ul>';
foreach ( $headers_array as $header ) {
if ( ! empty( $header ) ) {
echo '<li>' . esc_html( $header ) . '</li>';
}
}
echo '</ul>';
// In a real-world scenario, you'd add more sophisticated checks:
// - Content-Length, Content-Type
// - Cache-Control headers
// - Server response time (if available in headers)
// - Page load time (requires browser automation or more advanced JS execution simulation)
// - Lighthouse/PageSpeed Insights integration (via API)
wp_die(); // This is required to terminate immediately and return a proper response
}
?>
Frontend Integration and HTMX Attributes
The magic of dynamic updates without full page reloads is handled by HTMX. We’ve already added the necessary attributes in the `Save` function of our JavaScript block. The `hx-get` attribute points to our AJAX endpoint, `hx-trigger=”load”` ensures the request fires when the block is rendered on the frontend, and `hx-swap=”innerHTML”` dictates that the response from the AJAX call will replace the content within the target element.
<div class="antigravity-performance-diagnostic-block-frontend">
<p>Performance Diagnostic for: https://example.com</p>
<div class="antigravity-performance-diagnostic-block-output"
hx-get="/wp-admin/admin-ajax.php?action=antigravity_diagnose_performance&url=https%3A%2F%2Fexample.com&_ajax_nonce=YOUR_NONCE_HERE"
hx-trigger="load"
hx-swap="innerHTML"
hx-target=".antigravity-performance-diagnostic-block-output">
Loading performance data...
</div>
</div>
When a user views a page containing this block, HTMX will intercept the `load` event for the `.antigravity-performance-diagnostic-block-output` div. It will then make a GET request to the specified `hx-get` URL. The response from the `antigravity_diagnose_performance_callback` function (which contains the formatted HTML results) will then replace the “Loading performance data…” text within that same div.
Build Process and Dependencies
To compile the JavaScript and SCSS files, you’ll need a build process. WordPress development typically uses `@wordpress/scripts` which leverages Webpack. Ensure you have Node.js and npm/yarn installed.
# Navigate to your plugin directory cd /path/to/your/wordpress/plugins/custom-performance-diagnostic-block # Install dependencies npm install # Build for development (watches for changes) npm run start # Build for production npm run build
The `build/index.asset.php` file is automatically generated by `@wordpress/scripts` and contains the block’s dependencies and version, which is crucial for WordPress to correctly load scripts.
Security Considerations
Sanitization and validation are paramount. We’ve used `sanitize_url()` and `filter_var()` for the URL. The AJAX request is protected by a nonce (`check_ajax_referer`) to prevent Cross-Site Request Forgery (CSRF) attacks. Ensure that any external API calls or data processing within the AJAX handler are also secured against injection vulnerabilities.
Advanced Enhancements and Enterprise Use Cases
For enterprise-level applications, consider these extensions:
- Integration with Monitoring Services: Instead of basic cURL, use APIs for services like GTmetrix, Pingdom, or Google PageSpeed Insights to fetch detailed performance reports.
- Caching: Implement transient API caching for diagnostic results to avoid repeated external API calls and speed up frontend rendering.
- Scheduled Diagnostics: Use WordPress Cron (`wp_schedule_event`) to periodically run diagnostics on key pages and store results for historical trend analysis.
- Threshold Alerts: Define performance thresholds (e.g., load time > 3 seconds) and trigger notifications (email, Slack via webhook) when these are breached.
- User Role Permissions: Restrict who can configure or view the diagnostic block using WordPress capabilities.
- Data Visualization: Store diagnostic data in a custom database table and use JavaScript charting libraries (e.g., Chart.js) to visualize performance trends over time within the WordPress admin area.
- Multi-site Support: Ensure the plugin functions correctly across a WordPress multi-site network, potentially with network-activated settings.
- Internationalization: Properly internationalize all strings using `__()` and `_x()` for translation.
By leveraging Gutenberg’s extensibility and HTMX for dynamic client-side interactions, we can create powerful, non-intrusive diagnostic tools directly within the WordPress content management interface, providing valuable insights for CTOs and architects without requiring separate monitoring dashboards for basic checks.