• 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 real-time activity logs block for Gutenberg using HTMX dynamic attributes

Step-by-Step Guide to building a custom real-time activity logs block for Gutenberg using HTMX dynamic attributes

Leveraging HTMX for Real-Time Activity Logs in Gutenberg

Integrating dynamic, real-time activity logging directly into the WordPress Gutenberg editor presents a unique challenge. Traditional AJAX polling is often inefficient and can lead to a cluttered user experience. This guide details a robust approach using HTMX, specifically its dynamic attribute capabilities, to build a custom Gutenberg block that displays real-time activity logs without full page reloads or complex JavaScript frameworks. This solution is designed for CTOs and Enterprise Architects seeking efficient, scalable, and maintainable solutions for enhancing WordPress admin interfaces.

Core Architecture: HTMX and WordPress REST API

The fundamental principle is to decouple the log display from the main editor rendering. The Gutenberg block will act as a container, and HTMX will be responsible for fetching and updating the log content from a custom WordPress REST API endpoint. This endpoint will query the WordPress database for recent activity, formatted for efficient rendering.

Step 1: Setting Up the Custom REST API Endpoint

We need a dedicated REST API endpoint to serve the activity logs. This endpoint will be responsible for querying the database and returning the data in a format suitable for HTMX. We’ll use WordPress’s built-in REST API registration capabilities.

Registering the Endpoint

Create a new PHP file within your plugin or theme’s directory (e.g., wp-content/plugins/my-activity-log/my-activity-log.php) and register the endpoint.

<?php
/**
 * Plugin Name: My Activity Log
 * Description: Adds a real-time activity log block to Gutenberg.
 * Version: 1.0
 * Author: Your Name
 */

add_action( 'rest_api_init', function () {
    register_rest_route( 'my-activity-log/v1', '/logs', array(
        'methods'  => 'GET',
        'callback' => 'my_activity_log_get_logs',
        'permission_callback' => function () {
            // Ensure only authenticated users can access
            return current_user_can( 'read' );
        }
    ) );
} );

function my_activity_log_get_logs( WP_REST_Request $request ) {
    // Query for recent activity logs. For simplicity, we'll use a placeholder.
    // In a real-world scenario, you'd query a custom table or WP_Query with specific post types.
    $logs = array(
        array(
            'timestamp' => date( 'Y-m-d H:i:s' ),
            'user'      => wp_get_current_user()->display_name,
            'action'    => 'User viewed dashboard',
            'details'   => 'Accessed via REST API',
        ),
        array(
            'timestamp' => date( 'Y-m-d H:i:s', strtotime( '-1 minute' ) ),
            'user'      => 'Admin User',
            'action'    => 'Post published',
            'details'   => 'Post ID: 123',
        ),
    );

    // Simulate fetching from a more complex source
    // Example: Querying a custom log table
    /*
    global $wpdb;
    $table_name = $wpdb->prefix . 'activity_logs';
    $logs = $wpdb->get_results( "SELECT * FROM {$table_name} ORDER BY timestamp DESC LIMIT 10" );
    */

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

In a production environment, you would replace the hardcoded log data with actual database queries. This might involve creating a custom database table for logs or leveraging WordPress’s post types and meta data. The key is to return a JSON array of log entries.

Step 2: Creating the Gutenberg Block

We’ll create a custom Gutenberg block using JavaScript. This block will contain the HTMX attributes to manage the dynamic updates.

Block Registration (JavaScript)

Create a JavaScript file (e.g., wp-content/plugins/my-activity-log/src/block.js) and enqueue it properly. For this example, we’ll assume it’s enqueued via your plugin’s main PHP file.

// wp-content/plugins/my-activity-log/src/block.js

const { registerBlockType } = wp.blocks;
const { ServerSideRender } = wp.components;
const { Fragment } = wp.element;

registerBlockType( 'my-activity-log/real-time-logs', {
    title: 'Real-Time Activity Logs',
    icon: 'list-view',
    category: 'widgets',

    edit: () => {
        // The edit function for a server-side rendered block.
        // We'll handle the HTMX logic in the frontend rendering.
        return (
            <div>
                <h3>Activity Logs (Live)</h3>
                <p>Logs will appear here. This block is powered by HTMX.</p>
                { /* A placeholder for the actual rendered content */ }
            </div>
        );
    },

    save: () => {
        // The save function for a server-side rendered block.
        // We don't need to save static HTML for this dynamic block.
        // The rendering will be handled by the server.
        return null;
    },
} );

Enqueuing the Block Script

In your main plugin PHP file (my-activity-log.php), enqueue the script.

<?php
// ... (previous code) ...

function my_activity_log_register_block() {
    // Automatically load dependencies and version
    $asset_file = include( plugin_dir_path( __FILE__ ) . 'build/index.asset.php');

    wp_register_script(
        'my-activity-log-block-editor',
        plugin_dir_url( __FILE__ ) . 'build/index.js',
        $asset_file['dependencies'],
        $asset_file['version']
    );

    register_block_type( 'my-activity-log/real-time-logs', array(
        'editor_script' => 'my-activity-log-block-editor',
        // We'll use a server-side render callback to output the HTMX-enabled HTML
        'render_callback' => 'my_activity_log_render_block',
    ) );
}
add_action( 'init', 'my_activity_log_register_block' );

function my_activity_log_render_block( $attributes ) {
    // This function will output the HTML with HTMX attributes.
    // It will be called when the block is rendered on the frontend or in the editor preview.
    // We need to ensure HTMX is loaded.
    wp_enqueue_script( 'htmx-script', 'https://unpkg.com/[email protected]', array(), '1.9.10', true );

    ob_start();
    ?>
    <div
        id="activity-log-container"
        class="activity-log-wrapper"
        hx-get=""
        hx-trigger="every 5s"
        hx-swap="innerHTML"
    >
        <!-- Logs will be loaded here by HTMX -->
        Loading logs...
    </div>
    <?php
    return ob_get_clean();
}
?>

Note: For a real-world plugin, you’d use a build process (like Webpack) to compile your JavaScript and generate the index.asset.php file. The example above simplifies this by assuming a pre-compiled build/index.js and build/index.asset.php.

Step 3: Configuring HTMX Attributes

The magic happens in the my_activity_log_render_block function. We’re adding several key HTMX attributes to a wrapper `div`:

  • hx-get: Specifies the URL of the REST API endpoint to fetch data from. We use rest_url( 'my-activity-log/v1/logs' ) to dynamically get the correct REST API URL.
  • hx-trigger: Defines when the request should be made. "every 5s" means the logs will be refreshed every 5 seconds. This can be customized (e.g., load for initial load, click, custom events).
  • hx-swap: Determines how the fetched content should be placed into the DOM. "innerHTML" replaces the entire content of the `div` with the response from the server.

The initial content of the `div` (“Loading logs…”) serves as a placeholder until the first response is received.

Step 4: Styling the Activity Log

You’ll want to add some CSS to make the logs presentable. Create a CSS file (e.g., wp-content/plugins/my-activity-log/assets/css/style.css) and enqueue it.

/* wp-content/plugins/my-activity-log/assets/css/style.css */

.activity-log-wrapper {
    border: 1px solid #ddd;
    padding: 15px;
    margin-top: 20px;
    background-color: #f9f9f9;
    max-height: 300px;
    overflow-y: auto;
    font-size: 0.9em;
    border-radius: 4px;
}

.activity-log-wrapper h4 {
    margin-top: 0;
    color: #333;
    border-bottom: 1px solid #eee;
    padding-bottom: 5px;
}

.activity-log-item {
    margin-bottom: 10px;
    padding-bottom: 10px;
    border-bottom: 1px dashed #eee;
}

.activity-log-item:last-child {
    border-bottom: none;
    margin-bottom: 0;
    padding-bottom: 0;
}

.activity-log-timestamp {
    color: #888;
    font-style: italic;
    margin-right: 10px;
}

.activity-log-action {
    font-weight: bold;
    color: #555;
}

.activity-log-details {
    color: #666;
    margin-left: 5px;
}

Enqueue this CSS in your main plugin PHP file:

<?php
// ... (previous code) ...

function my_activity_log_enqueue_styles() {
    wp_enqueue_style(
        'my-activity-log-style',
        plugin_dir_url( __FILE__ ) . 'assets/css/style.css',
        array(),
        filemtime( plugin_dir_path( __FILE__ ) . 'assets/css/style.css' )
    );
}
add_action( 'admin_enqueue_scripts', 'my_activity_log_enqueue_styles' );
// Or 'wp_enqueue_scripts' if you want it on the frontend too.
?>

Step 5: Rendering the Log Entries (Server-Side)

The REST API endpoint currently returns raw JSON. HTMX will insert this JSON directly into the `innerHTML` of the target `div`. To render this nicely, we need to modify the REST API callback to return HTML, or use a client-side template with HTMX. Returning HTML from the server is often simpler for this use case.

Modifying the REST API Callback to Return HTML

We’ll change the `my_activity_log_get_logs` function to generate HTML snippets instead of JSON. This requires a slight adjustment to how the response is handled.

<?php
// ... (previous code) ...

function my_activity_log_get_logs( WP_REST_Request $request ) {
    // In a real scenario, fetch logs from DB
    $logs_data = array(
        array(
            'timestamp' => date( 'Y-m-d H:i:s' ),
            'user'      => wp_get_current_user()->display_name,
            'action'    => 'User viewed dashboard',
            'details'   => 'Accessed via REST API',
        ),
        array(
            'timestamp' => date( 'Y-m-d H:i:s', strtotime( '-1 minute' ) ),
            'user'      => 'Admin User',
            'action'    => 'Post published',
            'details'   => 'Post ID: 123',
        ),
        // Add more log entries for testing
        array(
            'timestamp' => date( 'Y-m-d H:i:s', strtotime( '-2 minutes' ) ),
            'user'      => 'Editor',
            'action'    => 'Comment approved',
            'details'   => 'Comment ID: 456',
        ),
    );

    // Generate HTML output
    ob_start();
    ?>
    <h4>Recent Activity</h4>
    <ul class="activity-log-list">
    <?php foreach ( $logs_data as $log ) : ?>
        <li class="activity-log-item">
            <span class="activity-log-timestamp"><?php echo esc_html( $log['timestamp'] ); ?></span>
            <span class="activity-log-action"><?php echo esc_html( $log['action'] ); ?></span>
            <span class="activity-log-details">- <?php echo esc_html( $log['details'] ); ?></span>
        </li>
    <?php endforeach; ?>
    </ul>
    <?php
    $html_output = ob_get_clean();

    // Return a WP_REST_Response with HTML content
    $response = new WP_REST_Response( $html_output, 200 );
    $response->set_content_type( 'text/html' ); // Crucial for HTMX to interpret as HTML
    return $response;
}
?>

By setting the Content-Type header to text/html, HTMX will correctly interpret the response and swap it into the target element.

Advanced Considerations and Optimizations

Database Performance

For high-traffic sites, querying the WordPress `posts` table for logs can become a bottleneck. Consider creating a dedicated `wp_activity_logs` table with appropriate indexes for `timestamp` and `user_id`. This allows for much faster retrieval of recent events.

Caching

While the logs are “real-time,” there’s a balance. If the underlying data doesn’t change every second, consider implementing server-side caching for the REST API endpoint. WordPress Transients API or object caching (e.g., Redis, Memcached) can be used. HTMX also has built-in caching capabilities (e.g., hx-cache attribute) that can be explored, though server-side caching is generally more robust.

Security and Permissions

The permission_callback in the REST API registration is critical. Ensure it strictly enforces who can view these logs. For enterprise environments, you might need more granular permissions based on user roles or specific capabilities.

Error Handling and Fallbacks

What happens if the REST API request fails? HTMX provides error handling attributes like hx-on::error. You can use this to display a fallback message or trigger alternative actions. Ensure the initial “Loading logs…” message is informative.

Scalability of Updates

The hx-trigger="every 5s" is simple but can lead to many concurrent requests if many users have the block open. For very large-scale deployments, consider alternative triggers or a more sophisticated pub/sub mechanism if true push-based updates are required (though HTMX excels at pull-based updates).

Conclusion

By combining WordPress’s REST API with HTMX’s declarative approach to dynamic updates, we can build highly efficient and maintainable real-time components within the Gutenberg editor. This pattern avoids the overhead of traditional JavaScript frameworks for simple dynamic content, offering a performant and developer-friendly solution for enhancing WordPress admin experiences. The separation of concerns—Gutenberg for UI structure, REST API for data, and HTMX for dynamic interaction—creates a robust and scalable architecture suitable for enterprise-level applications.

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: Implementing a secure lock mechanism for multi-worker Cron tasks with Shortcode API
  • Debugging and Resolving deep-seated hook priority conflicts in third-party Stripe Payment webhook connectors
  • Designing audit logs for enterprise WordPress setups tracking internal user modifications to user transaction ledgers
  • How to securely integrate OpenAI Completion API endpoints into WordPress custom plugins using WP HTTP API
  • WordPress Development Recipe: Leveraging Fiber lightweight concurrency to build type-safe, auto-wired hooks

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 (42)
  • 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 (114)
  • WordPress Plugin Development (118)
  • WordPress Plugin Development (330)
  • WordPress Theme Development (357)

Recent Posts

  • WordPress Development Recipe: Implementing a secure lock mechanism for multi-worker Cron tasks with Shortcode API
  • Debugging and Resolving deep-seated hook priority conflicts in third-party Stripe Payment webhook connectors
  • Designing audit logs for enterprise WordPress setups tracking internal user modifications to user transaction ledgers

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