• 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 React components

Step-by-Step Guide to building a custom automated performance diagnostic log block for Gutenberg using React components

Setting Up the WordPress Plugin and Development Environment

Before diving into React component development for Gutenberg, we need a robust WordPress plugin structure and a local development environment configured for modern JavaScript tooling. This involves setting up a basic plugin file, a `package.json` for dependency management, and a build process using tools like Webpack.

First, create a new directory for your plugin within the wp-content/plugins/ directory of your WordPress installation. Let’s name it performance-diagnostic-block.

Inside this directory, create the main plugin file, performance-diagnostic-block.php.

<?php
/**
 * Plugin Name: Performance Diagnostic Block
 * Description: A custom Gutenberg block to display performance diagnostic information.
 * Version: 1.0.0
 * Author: Your Name
 * License: GPL-2.0-or-later
 * Text Domain: performance-diagnostic-block
 */

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

/**
 * Registers the block using the metadata loaded from the `block.json` file.
 * Behind the scenes, it registers also all assets so they can be enqueued
 * through the block editor in the corresponding context.
 *
 * @see https://developer.wordpress.org/reference/functions/register_block_type/
 */
function performance_diagnostic_block_init() {
    register_block_type( __DIR__ . '/build' );
}
add_action( 'init', 'performance_diagnostic_block_init' );

Next, initialize npm in your plugin directory to manage JavaScript dependencies and build scripts.

cd wp-content/plugins/performance-diagnostic-block
npm init -y

Now, install the necessary development dependencies. We’ll need React, ReactDOM, and the Gutenberg `@wordpress/scripts` package, which provides a pre-configured Webpack setup for WordPress development.

npm install --save-dev @wordpress/scripts react react-dom

In your package.json file, add the following scripts to handle the build process:

{
  "name": "performance-diagnostic-block",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "wp-scripts build",
    "start": "wp-scripts start"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@wordpress/scripts": "^26.10.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  }
}

Create a block.json file in the root of your plugin directory. This file describes your block to WordPress and specifies its assets.

{
  "$schema": "https://schemas.wp.org/trunk/block.json",
  "apiVersion": 3,
  "name": "performance-diagnostic-block/diagnostic-info",
  "version": "0.1.0",
  "title": "Performance Diagnostic Info",
  "category": "widgets",
  "icon": "performance",
  "description": "Displays key performance metrics for the current page.",
  "keywords": [ "performance", "diagnostic", "speed", "metrics" ],
  "attributes": {
    "titleText": {
      "type": "string",
      "default": "Page Performance Metrics"
    },
    "showServerTime": {
      "type": "boolean",
      "default": true
    },
    "showDatabaseQueries": {
      "type": "boolean",
      "default": false
    }
  },
  "textdomain": "performance-diagnostic-block",
  "editorScript": "file:./build/index.js",
  "editorStyle": "file:./build/index.css",
  "style": "file:./build/style-index.css"
}

Finally, create a source directory (e.g., src/) for your JavaScript and CSS files. Inside src/, create index.js and edit.js.

mkdir src
touch src/index.js src/edit.js

The src/index.js file will be the entry point for your block’s JavaScript. It registers the block and imports the necessary components for the editor and frontend.

import { registerBlockType } from '@wordpress/blocks';
import './style.scss'; // For frontend styles
import './editor.scss'; // For editor styles

import Edit from './edit';
import save from './save'; // We'll create this later

registerBlockType( 'performance-diagnostic-block/diagnostic-info', {
    edit: Edit,
    save,
} );

To build your assets, run the following command in your terminal:

npm run build

This command will compile your JavaScript and CSS into the build/ directory, which is referenced in block.json and registered by your PHP file.

Developing the Gutenberg Editor Component with React

The edit.js file is where you’ll define the React component that renders your block in the Gutenberg editor. This component will handle user interactions, attribute management, and the visual representation of the block while editing.

Let’s start by creating a basic structure for src/edit.js. We’ll use components from the @wordpress/block-editor and @wordpress/components packages.

import { __ } from '@wordpress/i18n';
import {
    useBlockProps,
    InspectorControls,
} from '@wordpress/block-editor';
import { PanelBody, TextControl, ToggleControl } from '@wordpress/components';
import './editor.scss';

export default function Edit( { attributes, setAttributes } ) {
    const blockProps = useBlockProps();
    const { titleText, showServerTime, showDatabaseQueries } = attributes;

    const onChangeTitle = ( newTitle ) => {
        setAttributes( { titleText: newTitle } );
    };

    const onToggleServerTime = ( isChecked ) => {
        setAttributes( { showServerTime: isChecked } );
    };

    const onToggleDatabaseQueries = ( isChecked ) => {
        setAttributes( { showDatabaseQueries: isChecked } );
    };

    return (
        <>
            <InspectorControls>
                <PanelBody title={ __( 'Block Settings', 'performance-diagnostic-block' ) } initialOpen={ true }>
                    <TextControl
                        label={ __( 'Block Title', 'performance-diagnostic-block' ) }
                        value={ titleText }
                        onChange={ onChangeTitle }
                    />
                    <ToggleControl
                        label={ __( 'Show Server Time', 'performance-diagnostic-block' ) }
                        checked={ showServerTime }
                        onChange={ onToggleServerTime }
                    />
                    <ToggleControl
                        label={ __( 'Show Database Queries', 'performance-diagnostic-block' ) }
                        checked={ showDatabaseQueries }
                        onChange={ onToggleDatabaseQueries }
                    />
                </PanelBody>
            </InspectorControls>
            <div { ...blockProps }>
                <h3>{ titleText }</h3>
                <p>{ __( 'Editor Preview:', 'performance-diagnostic-block' ) }</p>
                { showServerTime && <p><strong>Server Time:</strong> (Preview)</p> }
                { showDatabaseQueries && <p><strong>Database Queries:</strong> (Preview)</p> }
                <p>{ __( 'Configure block settings in the sidebar.', 'performance-diagnostic-block' ) }</p>
            </div>
        </>
    );
}

In this edit.js component:

  • useBlockProps: A hook that provides necessary props for the block’s root element, including classes and attributes for proper editor integration.
  • InspectorControls: A component that renders settings in the block sidebar (Inspector).
  • PanelBody: A container for settings within the Inspector.
  • TextControl and ToggleControl: Input components for managing block attributes.
  • attributes and setAttributes: These are passed as props to the `Edit` component. `attributes` holds the current state of the block’s data, and `setAttributes` is a function to update that state.

We’ve defined three attributes in block.json: titleText (string), showServerTime (boolean), and showDatabaseQueries (boolean). The Edit component uses these attributes to render input fields in the sidebar and a preview within the editor.

After saving src/edit.js, run npm run build again to compile the changes. You should now be able to add your “Performance Diagnostic Info” block to a post or page in the WordPress editor and see the preview and sidebar controls.

Implementing the Frontend Save Component

The save function in your block’s JavaScript determines how the block is rendered on the frontend of your website. It should return JSX that represents the static HTML output of the block. For this block, we’ll create a src/save.js file.

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

export default function save( { attributes } ) {
    const blockProps = useBlockProps.save();
    const { titleText, showServerTime, showDatabaseQueries } = attributes;

    return (
        <div { ...blockProps }>
            <h3>{ titleText }</h3>
            <ul>
                { showServerTime && <li><strong>Server Time:</strong> <span class="performance-data" data-metric="server-time">Loading...</span></li> }
                { showDatabaseQueries && <li><strong>Database Queries:</strong> <span class="performance-data" data-metric="db-queries">Loading...</span></li> }
            </ul>
        </div>
    );
}

In src/save.js:

  • useBlockProps.save(): Similar to useBlockProps in the editor, but specifically for the frontend save function.
  • The returned JSX includes the titleText and conditionally renders list items for server time and database queries if their respective attributes are true.
  • We’ve added placeholder <span> elements with specific classes and data attributes (class="performance-data", data-metric="..."). These will be targeted by our JavaScript to dynamically populate the performance data.

Remember to update src/index.js to import and use this save function:

import { registerBlockType } from '@wordpress/blocks';
import './style.scss'; // For frontend styles
import './editor.scss'; // For editor styles

import Edit from './edit';
import save from './save'; // Import the save function

registerBlockType( 'performance-diagnostic-block/diagnostic-info', {
    edit: Edit,
    save, // Use the save function here
} );

Run npm run build again. Now, when you add the block to a page and publish it, the frontend will render the title and the selected metrics with “Loading…” placeholders.

Fetching and Displaying Performance Data with JavaScript

The final piece of the puzzle is to fetch the actual performance data and update the frontend. Since we’re dealing with server-side metrics, we’ll need a way to expose this data to the frontend JavaScript. A common and secure method is to use the WordPress REST API.

First, let’s create a REST API endpoint in your plugin’s PHP file to fetch the performance data. This endpoint will be responsible for gathering server time, database query counts, and potentially other metrics.

 'GET',
        'callback' => 'performance_diagnostic_block_get_metrics',
        'permission_callback' => '__return_true', // Adjust permissions as needed for production
    ) );
}
add_action( 'rest_api_init', 'performance_diagnostic_block_register_rest_route' );

/**
 * Callback function to get performance metrics.
 *
 * @return WP_REST_Response The response object.
 */
function performance_diagnostic_block_get_metrics() {
    $metrics = array();

    // Server Time (example: current server time)
    $metrics['server_time'] = date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) );

    // Database Queries (requires a plugin or custom query logging)
    // For demonstration, we'll use a placeholder or a simple count if available.
    // In a real-world scenario, you'd integrate with a query monitor plugin or WP_DEBUG_LOG.
    global $wpdb;
    if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
        $metrics['database_queries'] = count( $wpdb->queries );
    } else {
        // Fallback if SAVEQUERIES is not enabled.
        // You might want to log this to a transient or option if needed for debugging.
        $metrics['database_queries'] = 'SAVEQUERIES not enabled';
    }

    // Add more metrics here as needed (e.g., memory usage, execution time)

    return new WP_REST_Response( $metrics, 200 );
}

Important Security Note: The 'permission_callback' => '__return_true' is for demonstration purposes. In a production environment, you should implement proper permission checks to ensure only authorized users can access this data. This might involve checking user capabilities (e.g., current_user_can( 'manage_options' )).

Now, let’s create a JavaScript file to fetch data from this endpoint and update the frontend. Create a new file src/frontend.js.

document.addEventListener( 'DOMContentLoaded', () => {
    const performanceDataSpans = document.querySelectorAll( '.performance-data' );

    if ( performanceDataSpans.length === 0 ) {
        return; // No performance data spans found on this page
    }

    fetch( '/wp-json/performance-diagnostic-block/v1/metrics' )
        .then( response => {
            if ( ! response.ok ) {
                throw new Error( `HTTP error! status: ${ response.status }` );
            }
            return response.json();
        } )
        .then( data => {
            performanceDataSpans.forEach( span => {
                const metricType = span.dataset.metric;
                if ( data[metricType] !== undefined ) {
                    span.textContent = data[metricType];
                } else {
                    span.textContent = 'N/A'; // Metric not available
                }
            } );
        } )
        .catch( error => {
            console.error( 'Error fetching performance metrics:', error );
            performanceDataSpans.forEach( span => {
                span.textContent = 'Error loading data';
            } );
        } );
} );

This script:

  • Waits for the DOM to be fully loaded.
  • Selects all elements with the class .performance-data.
  • Fetches data from our custom REST API endpoint /wp-json/performance-diagnostic-block/v1/metrics.
  • Iterates through the fetched metrics and updates the textContent of the corresponding spans based on their data-metric attribute.
  • Includes basic error handling.

We need to enqueue this script for the frontend. Create a file named style.scss and editor.scss in your src/ directory for basic styling, and then modify your src/index.js to include frontend.js.

// src/index.js
import { registerBlockType } from '@wordpress/blocks';
import './style.scss'; // For frontend styles
import './editor.scss'; // For editor styles
import './frontend.js'; // Import the frontend script

import Edit from './edit';
import save from './save';

registerBlockType( 'performance-diagnostic-block/diagnostic-info', {
    edit: Edit,
    save,
} );

Now, update your block.json to include the frontend script. The @wordpress/scripts build process will automatically handle enqueuing scripts and styles listed in block.json for the editor and frontend contexts.

{
  "$schema": "https://schemas.wp.org/trunk/block.json",
  "apiVersion": 3,
  "name": "performance-diagnostic-block/diagnostic-info",
  "version": "0.1.0",
  "title": "Performance Diagnostic Info",
  "category": "widgets",
  "icon": "performance",
  "description": "Displays key performance metrics for the current page.",
  "keywords": [ "performance", "diagnostic", "speed", "metrics" ],
  "attributes": {
    "titleText": {
      "type": "string",
      "default": "Page Performance Metrics"
    },
    "showServerTime": {
      "type": "boolean",
      "default": true
    },
    "showDatabaseQueries": {
      "type": "boolean",
      "default": false
    }
  },
  "textdomain": "performance-diagnostic-block",
  "editorScript": "file:./build/index.js",
  "editorStyle": "file:./build/index.css",
  "style": "file:./build/style-index.css",
  "script": "file:./build/frontend.js"
}

Run npm run build one last time. After the build completes, activate your plugin in WordPress and visit a page where you’ve added the block. The “Loading…” placeholders should now be replaced with actual performance data fetched from your REST API endpoint.

Enhancements and Production Considerations

This setup provides a solid foundation. For production, consider these enhancements:

  • Error Handling & Fallbacks: Implement more robust error handling in both PHP and JavaScript. Provide clear messages to the user if data cannot be fetched.
  • Permissions: As mentioned, secure your REST API endpoint. Only allow access for users with appropriate roles (e.g., administrators, editors).
  • Data Caching: For frequently accessed, less volatile data, consider caching the REST API response to reduce server load.
  • Metric Selection: Allow users to select which specific metrics to display via the block’s attributes and UI.
  • Performance Optimization: For very high-traffic sites, ensure your REST API endpoint is efficient. Avoid heavy database queries directly in the callback if possible; consider pre-calculating or caching metrics.
  • Frontend Script Loading: Ensure frontend.js is only enqueued on pages where the block is actually used. Gutenberg’s block.json handles this automatically for the editor, but for the frontend, you might need conditional enqueuing in PHP if the block is not always present.
  • Internationalization: Ensure all user-facing strings are translatable using WordPress’s i18n functions (e.g., __(), _x()).
  • Styling: Add more comprehensive CSS for both the editor and frontend to ensure a polished look and feel.

By following these steps, you’ve built a custom, dynamic Gutenberg block that leverages React for the editor experience and fetches real-time data via the WordPress REST API for frontend display, offering a powerful tool for performance diagnostics directly within the WordPress admin.

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

  • WordPress Development Recipe: Leveraging Constructor Property Promotion to build type-safe, auto-wired hooks
  • How to design a modular Repository and Interface Structure architecture for enterprise-level custom plugins
  • Building secure B2B pricing grids with custom WP HTTP API endpoints and role overrides
  • Debugging and Resolving deep-seated hook priority conflicts in third-party Shopify headless API connectors
  • How to construct high-throughput import engines for large vendor commission records sets using custom XML/JSON parsers

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 (48)
  • 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 (155)
  • WordPress Plugin Development (180)
  • WordPress Plugin Development (330)
  • WordPress Theme Development (357)

Recent Posts

  • WordPress Development Recipe: Leveraging Constructor Property Promotion to build type-safe, auto-wired hooks
  • How to design a modular Repository and Interface Structure architecture for enterprise-level custom plugins
  • Building secure B2B pricing grids with custom WP HTTP API endpoints and role overrides

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