• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Step-by-Step Guide to building a custom automated performance diagnostic log block for Gutenberg using Vanilla JS Web Components

Step-by-Step Guide to building a custom automated performance diagnostic log block for Gutenberg using Vanilla JS Web Components

Understanding the Need for Automated Performance Diagnostics

WordPress, while incredibly flexible, can become a performance bottleneck if not managed carefully. Theme and plugin bloat, inefficient database queries, and unoptimized assets are common culprits. While tools like Query Monitor are invaluable for manual debugging, integrating performance insights directly into the content creation workflow can empower editors and developers alike to make more informed decisions. This post outlines the construction of a custom Gutenberg block that leverages Vanilla JavaScript Web Components to display automated performance diagnostic data.

Project Setup and Core Concepts

We’ll be building a Gutenberg block that, when activated, will fetch and display key performance metrics. This involves understanding a few core WordPress and web development concepts:

  • Gutenberg Blocks API: The foundation for building custom content elements in WordPress.
  • Web Components: A set of web platform APIs that allow you to create new custom, reusable, encapsulated HTML tags to use in web pages and web apps. We’ll use this for the UI of our diagnostic display.
  • JavaScript (Vanilla JS): For client-side logic, DOM manipulation, and API interaction.
  • WordPress REST API: To fetch performance data from the server.

For this example, we’ll assume a basic WordPress development environment is set up. We’ll create a simple plugin to house our block. Navigate to your WordPress plugins directory and create a new folder, e.g., wp-performance-diagnostics. Inside this folder, create a main plugin file, wp-performance-diagnostics.php.

Plugin Registration and Block Registration

First, let’s register our plugin and enqueue our JavaScript file for the block editor. We’ll also register the block itself using register_block_type.

wp-performance-diagnostics.php

<?php
/**
 * Plugin Name: WP Performance Diagnostics Block
 * Description: A custom Gutenberg block to display automated performance diagnostics.
 * Version: 1.0.0
 * Author: Your Name
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly.
}

/**
 * Register the block.
 */
function wp_performance_diagnostics_register_block() {
    // Automatically load dependencies and version.
    $asset_file = include( plugin_dir_path( __FILE__ ) . 'build/index.asset.php');

    register_block_type( 'wp-performance-diagnostics/diagnostics-block', array(
        'api_version'  => 2,
        'editor_script' => 'wp-performance-diagnostics-editor-script',
        'editor_style'  => 'wp-performance-diagnostics-editor-style',
        'style'         => 'wp-performance-diagnostics-style',
        'script'        => 'wp-performance-diagnostics-script', // This will be our Web Component script
        'attributes' => array(
            'message' => array(
                'type' => 'string',
                'default' => 'Performance Diagnostics',
            ),
        ),
    ) );
}
add_action( 'init', 'wp_performance_diagnostics_register_block' );

/**
 * Enqueue block editor assets.
 */
function wp_performance_diagnostics_editor_assets() {
    wp_enqueue_script(
        'wp-performance-diagnostics-editor-script',
        plugins_url( 'build/index.js', __FILE__ ),
        $asset_file['dependencies'],
        $asset_file['version']
    );

    wp_enqueue_style(
        'wp-performance-diagnostics-editor-style',
        plugins_url( 'build/index.css', __FILE__ ),
        array(),
        filemtime( plugin_dir_path( __FILE__ ) . 'build/index.css' )
    );
}
add_action( 'enqueue_block_editor_assets', 'wp_performance_diagnostics_editor_assets' );

/**
 * Enqueue frontend assets.
 */
function wp_performance_diagnostics_frontend_assets() {
    wp_enqueue_script(
        'wp-performance-diagnostics-script',
        plugins_url( 'build/web-component.js', __FILE__ ), // Our Web Component script
        array(), // No dependencies for this standalone component
        filemtime( plugin_dir_path( __FILE__ ) . 'build/web-component.js' ),
        true // Load in footer
    );

    wp_enqueue_style(
        'wp-performance-diagnostics-style',
        plugins_url( 'build/style.css', __FILE__ ),
        array(),
        filemtime( plugin_dir_path( __FILE__ ) . 'build/style.css' )
    );
}
add_action( 'wp_enqueue_scripts', 'wp_performance_diagnostics_frontend_assets' );

To manage JavaScript and CSS compilation, we’ll use a build process. A common setup involves @wordpress/scripts. Initialize a Node.js project in your plugin directory:

cd wp-performance-diagnostics
npm init -y
npm install @wordpress/scripts --save-dev

Add the following scripts to your package.json:

{
  "name": "wp-performance-diagnostics",
  "version": "1.0.0",
  "description": "",
  "main": "build/index.js",
  "scripts": {
    "build": "wp-scripts build",
    "start": "wp-scripts start"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@wordpress/scripts": "^27.0.0"
  }
}

Now, create a src directory within your plugin folder. Inside src, create index.js, index.css, and web-component.js. Also, create a style.css file at the root of your plugin directory.

Gutenberg Block Editor Implementation (src/index.js)

This file defines the block’s behavior within the Gutenberg editor. We’ll use @wordpress/blocks and @wordpress/element.

import { registerBlockType } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import { edit } from './edit'; // We'll create this component next
import { save } from './save'; // We'll create this component next
import './style.scss'; // For frontend styles
import './editor.scss'; // For editor styles

registerBlockType( 'wp-performance-diagnostics/diagnostics-block', {
    title: __( 'Performance Diagnostics', 'wp-performance-diagnostics' ),
    icon: 'performance', // WordPress dashicon
    category: 'widgets',
    attributes: {
        message: {
            type: 'string',
            default: 'Performance Diagnostics',
        },
    },
    edit: edit,
    save: save,
} );

Editor Component (src/edit.js)

This component handles the block’s appearance and controls in the editor. For this diagnostic block, we’ll keep it simple, perhaps just displaying the title and a placeholder.

import { __ } from '@wordpress/i18n';
import { useBlockProps } from '@wordpress/block-editor';
import { TextControl } from '@wordpress/components';

export function edit( { attributes, setAttributes } ) {
    const blockProps = useBlockProps();
    const { message } = attributes;

    return (
        <div { ...blockProps }>
            <h3>{ message }</h3>
            <p>{ __( 'This block will display performance metrics when viewed on the frontend.', 'wp-performance-diagnostics' ) }</p>
            <TextControl
                label={ __( 'Block Title', 'wp-performance-diagnostics' ) }
                value={ message }
                onChange={ ( newMessage ) => setAttributes( { message: newMessage } ) }
            />
        </div>
    );
}

Save Component (src/save.js)

This component defines the static HTML that will be saved to the post content. Crucially, it will render our custom Web Component.

import { useBlockProps } from '@wordpress/block-editor';

export function save( { attributes } ) {
    const blockProps = useBlockProps.save();
    const { message } = attributes;

    // We render our custom element here. The Web Component will handle its own rendering.
    return (
        <div { ...blockProps }>
            <h3>{ message }</h3>
            <performance-diagnostics-widget></performance-diagnostics-widget>
        </div>
    );
}

Web Component Implementation (src/web-component.js)

This is where the magic happens. We define a custom HTML element that will fetch and display performance data using Vanilla JavaScript. We’ll create a simple REST API endpoint to serve this data.

Backend: REST API Endpoint for Performance Data

Add this to your wp-performance-diagnostics.php file to create a REST API endpoint.

 WP_REST_Server::READABLE,
        'callback' => 'wp_performance_diagnostics_get_performance_data',
        'permission_callback' => function() {
            // Adjust permissions as needed. For simplicity, allow anyone.
            // In production, you'd likely want to check user capabilities.
            return true;
        }
    ) );
}
add_action( 'rest_api_init', 'wp_performance_diagnostics_register_rest_route' );

/**
 * Callback function to retrieve performance data.
 *
 * @param WP_REST_Request $request Full data.
 * @return WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
 */
function wp_performance_diagnostics_get_performance_data( WP_REST_Request $request ) {
    // In a real-world scenario, you'd gather metrics here.
    // For demonstration, we'll return mock data.
    $data = array(
        'php_version' => phpversion(),
        'memory_limit' => ini_get('memory_limit'),
        'max_execution_time' => ini_get('max_execution_time'),
        'wp_version' => get_bloginfo('version'),
        'database_queries' => 'N/A (requires integration with query monitor or similar)', // Placeholder
        'server_load' => 'N/A (requires server access)', // Placeholder
        'cache_status' => 'Enabled' // Placeholder
    );

    return new WP_REST_Response( $data, 200 );
}
?>

src/web-component.js

class PerformanceDiagnosticsWidget extends HTMLElement {
    constructor() {
        super();
        this.attachShadow({ mode: 'open' }); // Use Shadow DOM for encapsulation
        this.shadowRoot.innerHTML = `
            <style>
                :host {
                    display: block;
                    border: 1px solid #ccc;
                    padding: 15px;
                    margin-top: 10px;
                    background-color: #f9f9f9;
                    font-family: sans-serif;
                }
                .metric {
                    margin-bottom: 8px;
                }
                .metric strong {
                    display: inline-block;
                    width: 150px; /* Align labels */
                }
                .loading {
                    font-style: italic;
                    color: #888;
                }
                .error {
                    color: red;
                    font-weight: bold;
                }
            </style>
            <div id="diagnostics-container">
                <p class="loading">Loading performance data...</p>
            </div>
        `;
        this.container = this.shadowRoot.getElementById('diagnostics-container');
    }

    connectedCallback() {
        this.fetchPerformanceData();
    }

    async fetchPerformanceData() {
        try {
            const response = await fetch('/wp-json/wp-performance-diagnostics/v1/performance-data');
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            const data = await response.json();
            this.renderData(data);
        } catch (error) {
            console.error('Error fetching performance data:', error);
            this.renderError(error);
        }
    }

    renderData(data) {
        this.container.innerHTML = ''; // Clear loading message
        for (const key in data) {
            const metricElement = document.createElement('div');
            metricElement.classList.add('metric');
            metricElement.innerHTML = `<strong>${this.formatKey(key)}:</strong> ${data[key]}`;
            this.container.appendChild(metricElement);
        }
    }

    renderError(error) {
        this.container.innerHTML = ''; // Clear loading message
        const errorElement = document.createElement('p');
        errorElement.classList.add('error');
        errorElement.textContent = `Failed to load performance data: ${error.message}`;
        this.container.appendChild(errorElement);
    }

    formatKey(key) {
        // Basic formatting for display
        return key.replace(/_/g, ' ').replace(/\b\w/g, char => char.toUpperCase());
    }
}

// Define the custom element if it hasn't been defined yet
if (!customElements.get('performance-diagnostics-widget')) {
    customElements.define('performance-diagnostics-widget', PerformanceDiagnosticsWidget);
}

Styling (src/style.scss and src/editor.scss)

These files handle the styling for the block, both in the editor and on the frontend. For the Web Component, styles are encapsulated within its Shadow DOM.

src/style.scss (Frontend Styles)

.wp-block-wp-performance-diagnostics-diagnostics-block {
    border: 1px dashed #0073aa;
    padding: 15px;
    margin-bottom: 20px;
    background-color: #eaf4fa;
}

.wp-block-wp-performance-diagnostics-diagnostics-block h3 {
    margin-top: 0;
    color: #005177;
}

src/editor.scss (Editor Styles)

.wp-block-wp-performance-diagnostics-diagnostics-block {
    border: 1px solid #0073aa;
    padding: 15px;
    background-color: #f0f8ff;
}

.wp-block-wp-performance-diagnostics-diagnostics-block h3 {
    margin-top: 0;
    color: #005177;
}

Build Process and Activation

Navigate to your plugin’s root directory in the terminal and run the build command:

npm run build

This command will compile your SCSS files and JavaScript into the build directory. After the build completes, activate the “WP Performance Diagnostics Block” plugin in your WordPress admin area. You should now be able to add the “Performance Diagnostics” block to your posts or pages.

Testing and Further Enhancements

Add the block to a page and view it on the frontend. The “Loading performance data…” message should be replaced with the actual metrics fetched from the REST API. This basic implementation can be extended significantly:

  • Real-time Data: Integrate with server monitoring tools or WordPress plugins (like Query Monitor) to fetch more dynamic data (e.g., current database query count, memory usage).
  • User Roles: Conditionally display the block or specific metrics based on the logged-in user’s role.
  • Configuration: Allow users to select which metrics to display via block attributes.
  • Error Handling: Implement more robust error reporting and fallback mechanisms.
  • Performance Budgeting: Compare fetched metrics against predefined thresholds and visually indicate potential issues.
  • Caching: Implement client-side caching for the fetched data to avoid repeated API calls on every page load.
  • Server-Side Rendering (SSR): For critical performance data, consider rendering the initial metrics server-side to avoid the “flash” of loading content.

By combining the power of Gutenberg blocks with the encapsulation of Web Components and the flexibility of the WordPress REST API, you can create highly customized and informative tools directly within the WordPress content editor.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Step-by-Step Guide to building a custom Elasticsearch search bar block for Gutenberg using Alpine.js lightweight states
  • How to implement native Redis caching layers for high-volume custom taxonomy queries in Sage Roots modern environments
  • How to design secure Zapier dynamic webhooks webhook listeners using signature validation and payload queues
  • WordPress Development Recipe: Real-time custom event triggers using WebSockets and Metadata API (add_post_meta)
  • Optimizing p99 database query response latency in multi-site Singleton Registry Pattern custom tables

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (658)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (872)
  • PHP (5)
  • PHP Development (41)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Server (23)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (69)
  • WordPress Plugin Development (76)
  • WordPress Plugin Development (330)
  • WordPress Theme Development (357)

Recent Posts

  • Step-by-Step Guide to building a custom Elasticsearch search bar block for Gutenberg using Alpine.js lightweight states
  • How to implement native Redis caching layers for high-volume custom taxonomy queries in Sage Roots modern environments
  • How to design secure Zapier dynamic webhooks webhook listeners using signature validation and payload queues

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (872)
  • Debugging & Troubleshooting (658)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Business & Monetization (390)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala