• 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 REST API custom routes

Step-by-Step Guide to building a custom automated performance diagnostic log block for Gutenberg using REST API custom routes

Defining the Performance Diagnostic Log Block

This guide details the construction of a custom Gutenberg block designed to capture and display performance diagnostic logs directly within the WordPress editor. This empowers content creators and administrators to embed real-time performance metrics or historical diagnostic data into their pages and posts, offering immediate context for performance-related content. We will leverage WordPress’s REST API to create custom routes for data retrieval and manipulation, ensuring a robust and scalable solution.

Backend: Custom REST API Endpoint for Log Retrieval

The core of our solution lies in a custom REST API endpoint that will serve performance log data. This endpoint will be accessible from the frontend and will be queried by our Gutenberg block. We’ll implement this using PHP within your WordPress theme’s `functions.php` file or a custom plugin.

First, we register a new REST API route. This route will be responsible for fetching log data. For demonstration purposes, we’ll simulate fetching log entries. In a production environment, this would involve querying a custom log table, a dedicated logging service, or parsing log files.

Registering the REST API Route

We use the `rest_api_init` action hook to register our custom endpoint. The route will be `/myplugin/v1/performance-logs`. We’ll define a callback function that handles the GET request.

add_action( 'rest_api_init', function () {
    register_rest_route( 'myplugin/v1', '/performance-logs', array(
        'methods'  => 'GET',
        'callback' => 'myplugin_get_performance_logs',
        'permission_callback' => function () {
            // Ensure only authenticated users with sufficient capabilities can access.
            // Adjust 'edit_posts' capability as needed.
            return current_user_can( 'edit_posts' );
        }
    ) );
} );

Implementing the Callback Function

The `myplugin_get_performance_logs` function will be responsible for fetching and formatting the log data. For this example, we’ll return a hardcoded array of log entries. In a real-world scenario, this function would interact with your logging mechanism.

function myplugin_get_performance_logs( WP_REST_Request $request ) {
    // Simulate fetching performance log data.
    // In a real application, this would query a database, log file, or external service.
    $logs = array(
        array(
            'timestamp' => current_time( 'mysql' ),
            'level'     => 'INFO',
            'message'   => 'Page load time: 1.2s',
            'details'   => array(
                'dns_lookup' => '0.1s',
                'tcp_connect' => '0.2s',
                'ssl_handshake' => '0.3s',
                'ttfb' => '0.6s',
                'dom_interactive' => '0.9s',
                'dom_complete' => '1.2s'
            )
        ),
        array(
            'timestamp' => date( 'Y-m-d H:i:s', strtotime( '-5 minutes' ) ),
            'level'     => 'WARNING',
            'message'   => 'High database query count detected.',
            'details'   => array(
                'query_count' => 150,
                'slow_queries' => 5
            )
        ),
        array(
            'timestamp' => date( 'Y-m-d H:i:s', strtotime( '-10 minutes' ) ),
            'level'     => 'ERROR',
            'message'   => 'External API request timed out.',
            'details'   => array(
                'api_endpoint' => 'https://api.example.com/data',
                'timeout' => '5s'
            )
        )
    );

    // You might want to add pagination or filtering based on $request parameters.
    // For example: $page = $request->get_param( 'page' ) ?: 1;

    $response = new WP_REST_Response( $logs, 200 );
    $response->header( 'Content-Type', 'application/json' );
    return $response;
}

// Ensure the function is defined before it's called.
// This is typically handled by WordPress's loading order if placed in functions.php or a plugin.

Frontend: Gutenberg Block Development

Now, we’ll develop the Gutenberg block. This involves creating JavaScript files for the block’s editor interface and its frontend rendering. We’ll use the `@wordpress/scripts` package for building our JavaScript assets.

Project Setup and Dependencies

Navigate to your theme’s directory or your plugin’s directory. If you don’t have a `package.json` file, create one:

npm init -y

Install the necessary WordPress scripts package:

npm install @wordpress/scripts --save-dev

Add build scripts to your `package.json`:

{
  "name": "my-performance-block",
  "version": "1.0.0",
  "scripts": {
    "build": "wp-scripts build",
    "start": "wp-scripts start"
  },
  "devDependencies": {
    "@wordpress/scripts": "^26.0.0"
  }
}

Block Registration (`block.json`)

Create a `block.json` file in your block’s directory (e.g., `wp-content/themes/your-theme/blocks/performance-log/block.json`). This file describes your block to WordPress.

{
  "$schema": "https://schemas.wp.org/trunk/block.json",
  "apiVersion": 3,
  "name": "myplugin/performance-log",
  "version": "0.1.0",
  "title": "Performance Diagnostic Log",
  "category": "widgets",
  "icon": "performance",
  "description": "Displays performance diagnostic logs.",
  "attributes": {
    "logCount": {
      "type": "number",
      "default": 5
    }
  },
  "editorScript": "file:./index.js",
  "editorStyle": "file:./index.css",
  "style": "file:./style-index.css",
  "render": "file:./render.php"
}

Editor JavaScript (`src/index.js`)

This file registers the block and defines its behavior in the editor. We’ll use `registerBlockType` from `@wordpress/blocks` and `apiFetch` from `@wordpress/api-fetch` to get our log data.

import { registerBlockType } from '@wordpress/blocks';
import { useSelect } from '@wordpress/data';
import { apiFetch } from '@wordpress/api-fetch';
import { InspectorControls } from '@wordpress/block-editor';
import { PanelBody, RangeControl } from '@wordpress/components';
import { Fragment } from '@wordpress/element';

import './style.scss'; // For frontend styles
import './editor.scss'; // For editor-specific styles

const blockName = 'myplugin/performance-log';

registerBlockType( blockName, {
    apiVersion: 3,
    title: 'Performance Diagnostic Log',
    icon: 'performance',
    category: 'widgets',
    description: 'Displays performance diagnostic logs.',
    attributes: {
        logCount: {
            type: 'number',
            default: 5,
        },
    },

    edit: ( { attributes, setAttributes } ) => {
        const { logCount } = attributes;

        // Fetch logs using apiFetch
        const logs = useSelect( ( select ) => {
            return select( 'core' ).getEntityRecords( 'root', 'myplugin/v1/performance-logs', { per_page: logCount } );
        }, [ logCount ] );

        const isLoading = useSelect( ( select ) => {
            return select( 'core' ).isResolving( 'core', 'getEntityRecords', [ 'root', 'myplugin/v1/performance-logs', { per_page: logCount } ] );
        }, [ logCount ] );

        const errorMessage = useSelect( ( select ) => {
            return select( 'core' ).get andError( 'core', 'getEntityRecords', [ 'root', 'myplugin/v1/performance-logs', { per_page: logCount } ] );
        }, [ logCount ] );

        const renderLogEntry = ( log, index ) => (
            <li key={ index }>
                <strong>[{ log.timestamp }] { log.level}:</strong> { log.message }
                { log.details && Object.keys( log.details ).length > 0 && (
                    <ul>
                        { Object.entries( log.details ).map( ( [key, value] ) => (
                            <li key={ key }>{ key }: { typeof value === 'object' ? JSON.stringify( value ) : value }</li>
                        ) ) }
                    </ul>
                ) }
            </li>
        );

        return (
            <>
                <InspectorControls>
                    <PanelBody title="Log Settings">
                        <RangeControl
                            label="Number of Logs to Display"
                            value={ logCount }
                            onChange={ ( newCount ) => setAttributes( { logCount: newCount } ) }
                            min={ 1 }
                            max={ 10 }
                        />
                    </PanelBody>
                </InspectorControls>
                <div className="wp-block-myplugin-performance-log">
                    <h3>Performance Logs (Editor Preview)</h3>
                    { isLoading && <p>Loading logs...</p> }
                    { errorMessage && <p style={{ color: 'red' }}>Error loading logs: { errorMessage.message }</p> }
                    { !isLoading && !errorMessage && logs && logs.length > 0 && (
                        <ul>
                            { logs.slice( 0, logCount ).map( renderLogEntry ) }
                        </ul>
                    ) }
                    { !isLoading && !errorMessage && ( !logs || logs.length === 0 ) && <p>No logs found.</p> }
                </div>
            </>
        );
    },

    save: () => {
        // The frontend rendering will be handled by PHP (render.php)
        // This function can return null or a placeholder if server-side rendering is used.
        return null;
    },
} );

Editor Styles (`src/editor.scss`)

Basic styling for the block in the editor.

.wp-block-myplugin-performance-log {
    border: 1px solid #ccc;
    padding: 15px;
    background-color: #f9f9f9;
    margin-bottom: 1em;

    h3 {
        margin-top: 0;
        color: #333;
    }

    ul {
        list-style: disc inside;
        padding-left: 20px;
    }

    li {
        margin-bottom: 0.5em;
    }
}

Frontend Styles (`src/style.scss`)

Styles that will be applied to the block on the frontend.

.wp-block-myplugin-performance-log {
    border: 1px solid #e0e0e0;
    padding: 20px;
    background-color: #ffffff;
    margin-bottom: 2em;
    font-family: sans-serif;
    font-size: 0.9em;

    h3 {
        margin-top: 0;
        color: #555;
        border-bottom: 1px solid #eee;
        padding-bottom: 10px;
        margin-bottom: 15px;
    }

    ul {
        list-style: none;
        padding-left: 0;
    }

    li {
        margin-bottom: 0.8em;
        padding-left: 15px;
        position: relative;

        &:before {
            content: '•';
            color: #0073aa;
            font-weight: bold;
            display: inline-block;
            width: 1em;
            margin-left: -1em;
            position: absolute;
            left: 0;
        }
    }

    strong {
        color: #333;
    }

    .log-level-INFO { color: green; }
    .log-level-WARNING { color: orange; }
    .log-level-ERROR { color: red; }

    .log-details {
        margin-top: 5px;
        padding-left: 20px;
        font-size: 0.95em;
        color: #666;
        border-left: 2px solid #f0f0f0;
    }
}

Server-Side Rendering (`render.php`)

Since we’re fetching data from the REST API, server-side rendering (SSR) is a good approach for the frontend. This ensures the data is available immediately on page load, improving perceived performance and SEO. The `render.php` file defined in `block.json` will be executed on the server.

<?php
/**
 * Server-side rendering for the Performance Diagnostic Log block.
 *
 * @package MyPlugin
 */

// Ensure this file is only included within the WordPress environment.
if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly.
}

// Get attributes passed from the block.
$log_count = isset( $attributes['logCount'] ) ? (int) $attributes['logCount'] : 5;

// Fetch logs via REST API.
// Note: In a real-world scenario, you might want to cache this response
// or use a more direct method if performance is critical and the API is internal.
$request_url = rest_url( 'myplugin/v1/performance-logs' );
$response = wp_remote_get( $request_url );

$logs = array();
if ( ! is_wp_error( $response ) && $response['response']['code'] === 200 ) {
    $body = wp_remote_retrieve_body( $response );
    $logs_data = json_decode( $body, true );
    if ( is_array( $logs_data ) ) {
        $logs = array_slice( $logs_data, 0, $log_count );
    }
}

?>
<div class="wp-block-myplugin-performance-log">
    <h3>Performance Logs</h3>
    <?php if ( ! empty( $logs ) ) : ?>
        <ul>
            <?php foreach ( $logs as $log ) : ?>
                <li class="log-entry log-level-<?php echo esc_attr( strtoupper( $log['level'] ?? 'UNKNOWN' ) ); ?>">
                    <strong>[<?php echo esc_html( $log['timestamp'] ?? '' ); ?>] <?php echo esc_html( $log['level'] ?? '' ); ?>:</strong> <?php echo esc_html( $log['message'] ?? '' ); ?>
                    <?php if ( ! empty( $log['details'] ) && is_array( $log['details'] ) ) : ?>
                        <div class="log-details">
                            <strong>Details:</strong>
                            <ul>
                                <?php foreach ( $log['details'] as $key => $value ) : ?>
                                    <li><?php echo esc_html( $key ); ?>: <?php echo esc_html( is_array( $value ) ? json_encode( $value ) : $value ); ?></li>
                                </?php endforeach; ?>
                            </ul>
                        </div>
                    <?php endif; ?>
                </li>
            <?php endforeach; ?>
        </ul>
    <?php else : ?>
        <p>No performance logs available or an error occurred fetching them.</p>
    <?php endif; ?>
</div>

Building the Assets

Run the build command in your terminal from the directory containing `package.json`:

npm run build

This will compile your SCSS files and JavaScript into production-ready assets, typically placed in a `build` directory. You’ll need to enqueue these assets in your theme’s `functions.php` or plugin file.

Enqueuing Block Assets

Register and enqueue the block’s assets. This is crucial for the block to function correctly both in the editor and on the frontend.

function myplugin_register_performance_log_block() {
    // Register the block. The 'editorScript' and 'editorStyle' from block.json
    // handle the editor-side assets. We need to enqueue the frontend styles.

    // Enqueue frontend styles if they are not already handled by block.json's 'style' property.
    // The 'style' property in block.json usually handles this automatically.
    // If you need more control or have separate frontend JS, you'd enqueue them here.

    // Example of enqueuing a separate frontend JS file if needed:
    // wp_enqueue_script(
    //     'myplugin-performance-log-frontend',
    //     plugins_url( 'build/frontend.js', __FILE__ ), // Adjust path as necessary
    //     array( 'wp-element', 'wp-api-fetch' ),
    //     filemtime( plugin_dir_path( __FILE__ ) . 'build/frontend.js' )
    // );

    // Ensure the block is registered. This is often done implicitly by WordPress
    // when it finds a block.json file, but explicit registration can be done.
    register_block_type( __DIR__ . '/blocks/performance-log' ); // Assuming block.json is here
}
add_action( 'init', 'myplugin_register_performance_log_block' );

Testing and Deployment

After implementing the backend API route and the Gutenberg block, you can test the functionality. Add the “Performance Diagnostic Log” block to a post or page in the WordPress editor. You should see a preview of the logs. Publish the post/page and view it on the frontend to confirm the logs are displayed correctly.

For production deployment:

  • Ensure the REST API route is accessible and secured appropriately.
  • The `npm run build` command should be part of your deployment pipeline.
  • The compiled assets (JavaScript and CSS) must be deployed to the server.
  • Consider caching strategies for the REST API endpoint if it becomes a performance bottleneck itself.

Advanced Considerations

Security: The `permission_callback` in `register_rest_route` is crucial. Ensure it aligns with your security requirements. For sensitive data, consider more granular capabilities or role-based access.

Performance of the API: If your log data source is slow, the REST API endpoint can become a bottleneck. Implement caching (e.g., using `wp_cache_set` and `wp_cache_get`) or optimize your data retrieval queries.

Error Handling: Enhance error handling in both the PHP callback and the JavaScript `edit` function to provide more informative feedback to the user.

Data Visualization: For more complex performance data, consider integrating charting libraries (e.g., Chart.js) within the block’s editor or frontend rendering to visualize trends.

Log Management: For production systems, a dedicated logging solution (like ELK stack, Splunk, or cloud-based services) is recommended over simple file or database logging. Your REST API would then interface with this system.

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

  • How to securely integrate Firebase Realtime DB endpoints into WordPress custom plugins using Rewrite API custom endpoints
  • How to securely integrate PayPal Checkout REST endpoints into WordPress custom plugins using Transients API
  • Implementing automated compliance reporting for custom online course lessons ledgers using dompdf library
  • How to build custom WooCommerce core overrides extensions utilizing modern Block Patterns API schemas
  • How to securely integrate AWS S3 file uploads endpoints into WordPress custom plugins using WP HTTP API

Categories

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

Recent Posts

  • How to securely integrate Firebase Realtime DB endpoints into WordPress custom plugins using Rewrite API custom endpoints
  • How to securely integrate PayPal Checkout REST endpoints into WordPress custom plugins using Transients API
  • Implementing automated compliance reporting for custom online course lessons ledgers using dompdf library

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (818)
  • Debugging & Troubleshooting (603)
  • Security & Compliance (581)
  • 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