• 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 » How to build custom Timber Twig templating engines extensions utilizing modern Heartbeat API schemas

How to build custom Timber Twig templating engines extensions utilizing modern Heartbeat API schemas

Leveraging the Heartbeat API for Dynamic Timber/Twig Extensions

WordPress’s Heartbeat API, often overlooked beyond its basic AJAX polling for autosave and session management, presents a powerful, albeit underutilized, mechanism for real-time data synchronization and dynamic content manipulation within themes and plugins. When combined with Timber and its Twig templating engine, the Heartbeat API unlocks sophisticated patterns for building highly interactive and responsive user interfaces without resorting to full page reloads or complex JavaScript frameworks. This post details how to architect and implement custom Timber/Twig extensions that react to and leverage Heartbeat events, providing a robust foundation for advanced WordPress development.

Understanding Heartbeat API Schemas and Hooks

The Heartbeat API operates on a request-response cycle, triggered by JavaScript in the browser and handled by PHP on the server. The core interaction points are the heartbeat_send filter and the heartbeat_tick action. The heartbeat_send filter allows us to inject data into the Heartbeat payload sent from the server to the client. Conversely, the heartbeat_tick action is executed on the server when a Heartbeat request is received, providing an opportunity to perform server-side logic based on the incoming data or to prepare data for the next client-side tick.

The data exchanged via Heartbeat is typically structured as an associative array. For custom extensions, it’s crucial to define a clear schema for the data you intend to send and receive. This schema should be documented and consistently applied across your PHP and JavaScript implementations. A common pattern is to prefix your custom data keys with a unique identifier to avoid conflicts with WordPress core or other plugins.

Server-Side Data Injection with heartbeat_send

To inject custom data into the Heartbeat payload, we hook into the heartbeat_send filter. This filter receives the current Heartbeat data array and should return a modified array. This is the primary method for pushing dynamic server-side information to the client for use in Twig templates.

Example: Pushing User-Specific Settings

Let’s imagine a scenario where we want to dynamically update a user’s notification count or a real-time status indicator within a Timber-rendered dashboard. We can push this data via Heartbeat.

PHP Implementation (functions.php or plugin file)

/**
 * Inject custom data into the Heartbeat API payload.
 *
 * @param array $data The current Heartbeat data.
 * @return array The modified Heartbeat data.
 */
function my_custom_heartbeat_data( $data ) {
    // Ensure we are in the admin area or a specific context where this is relevant.
    // For front-end, you'd typically enqueue a script that initiates Heartbeat.
    if ( ! is_admin() ) {
        // You might want to check for specific page templates or conditions here.
        // For example: if ( is_page_template( 'template-dashboard.php' ) ) { ... }
        // Or if you've explicitly initialized Heartbeat on the front-end.
    }

    // Example: Fetching a user-specific notification count.
    $user_id = get_current_user_id();
    if ( $user_id ) {
        // Replace with your actual notification fetching logic.
        $notification_count = get_user_meta( $user_id, 'my_custom_notifications', true );
        $data['my_plugin_heartbeat']['notification_count'] = intval( $notification_count ?: 0 );
    }

    // Example: Pushing a real-time status.
    $data['my_plugin_heartbeat']['server_status'] = 'online'; // Or fetch dynamic status.

    // Add a timestamp to ensure cache busting or for client-side logic.
    $data['my_plugin_heartbeat']['timestamp'] = time();

    return $data;
}
add_filter( 'heartbeat_send', 'my_custom_heartbeat_data', 10, 1 );

In this example, we’ve added a custom array key my_plugin_heartbeat to the Heartbeat data. This namespace helps prevent collisions. Inside, we push notification_count and server_status. The timestamp is useful for client-side validation or triggering updates.

Client-Side Data Consumption and Twig Integration

On the client-side, WordPress’s core JavaScript enqueues the Heartbeat API. We can hook into the heartbeat-send JavaScript event to intercept the data being sent from the server and then update our Twig templates or trigger other JavaScript logic. Timber provides a convenient way to pass data to Twig, and we can dynamically update this data using JavaScript.

JavaScript Implementation

(function($) {
    // Ensure Heartbeat is enabled. It's usually enqueued by default in admin.
    // For front-end, you'd need to enqueue the heartbeat script and potentially
    // call wp.heartbeat.connect() if not automatically initiated.
    if (typeof wp !== 'undefined' && typeof wp.heartbeat !== 'undefined') {

        // Hook into the heartbeat-send event
        $(document).on('heartbeat-send', function(e, data) {
            // Add custom data to be sent to the server (optional for this example)
            // data.my_custom_data = { 'action': 'my_plugin_action' };

            // The server will send back data via the 'heartbeat-tick' event.
            // We'll process that data on the 'heartbeat-tick' event.
        });

        // Hook into the heartbeat-tick event to receive data from the server
        $(document).on('heartbeat-tick', function(e, data) {
            // Check if our custom data is present
            if (data['my_plugin_heartbeat']) {
                var pluginData = data['my_plugin_heartbeat'];

                // Update notification count in the DOM if it exists
                if (pluginData.notification_count !== undefined) {
                    var $notificationElement = $('#my-notification-count'); // Assume an element with this ID exists
                    if ($notificationElement.length) {
                        $notificationElement.text(pluginData.notification_count);
                        // You might also want to add/remove classes for visual feedback
                        if (pluginData.notification_count > 0) {
                            $notificationElement.addClass('has-notifications');
                        } else {
                            $notificationElement.removeClass('has-notifications');
                        }
                    }
                }

                // Update server status
                if (pluginData.server_status !== undefined) {
                    var $statusElement = $('#server-status-indicator'); // Assume an element with this ID exists
                    if ($statusElement.length) {
                        $statusElement.text('Status: ' + pluginData.server_status);
                        // Update class based on status
                        $statusElement.removeClass('status-online status-offline').addClass('status-' + pluginData.server_status);
                    }
                }

                // You can also trigger custom events or update other parts of your UI
                // $(document).trigger('my_plugin_heartbeat_updated', [pluginData]);
            }
        });

        // Optional: Handle Heartbeat errors
        $(document).on('heartbeat-error', function(e, error) {
            console.error('Heartbeat Error:', error);
            // Implement fallback or error display logic
        });

        // Optional: Manually connect to Heartbeat if not automatically initiated
        // wp.heartbeat.connect();
    }
})(jQuery);

This JavaScript snippet listens for the heartbeat-tick event. When it fires, it checks for our my_plugin_heartbeat data. If found, it updates specific DOM elements (e.g., a notification count display, a status indicator) with the received values. This assumes you have corresponding HTML elements in your Twig template with specific IDs.

Twig Template Integration

In your Timber-rendered Twig template, you’ll need to output the initial state of these elements and ensure they have the correct IDs for the JavaScript to target. The initial values can be passed from your PHP Timber context.

{# Example: dashboard.twig #}
<div class="dashboard-widgets">
    <div class="widget notification-widget">
        <h3>Notifications</h3>
        <p>You have <span id="my-notification-count">{{ initial_notification_count | default(0) }}</span> new notifications.</p>
    </div>

    <div class="widget server-status-widget">
        <h3>Server Status</h3>
        <p><span id="server-status-indicator" class="status-{{ initial_server_status | default('unknown') }}">Status: {{ initial_server_status | default('Unknown') }}</span></p>
    </div>
</div>

The PHP code that renders this template would pass the initial values:

// In your Timber context rendering function (e.g., in functions.php or a custom controller)
function render_dashboard_page() {
    $user_id = get_current_user_id();
    $initial_notification_count = $user_id ? get_user_meta( $user_id, 'my_custom_notifications', true ) : 0;

    $context = Timber::context();
    $context['initial_notification_count'] = intval( $initial_notification_count ?: 0 );
    $context['initial_server_status'] = 'online'; // Default or fetch initial status

    Timber::render( 'dashboard.twig', $context );
}

Server-Side Logic with heartbeat_tick

While heartbeat_send is for *sending* data, heartbeat_tick is an action that fires *on the server* whenever a Heartbeat request is received. This is useful for performing server-side tasks in response to a client ping, such as background processing, cache invalidation, or updating transient data. You can also use it to *prepare* data for the next heartbeat_send cycle.

Example: Server-Side Data Processing

/**
 * Process server-side logic on each Heartbeat tick.
 *
 * @param array $response The Heartbeat response data.
 * @param array $data The data received from the client (if any).
 * @return array The modified Heartbeat response data.
 */
function my_custom_heartbeat_tick_handler( $response, $data ) {
    // Check if our plugin is sending specific data for processing.
    if ( isset( $data['my_plugin_heartbeat'] ) && isset( $data['my_plugin_heartbeat']['action'] ) ) {
        $action = $data['my_plugin_heartbeat']['action'];

        switch ( $action ) {
            case 'reset_notifications':
                $user_id = get_current_user_id();
                if ( $user_id ) {
                    delete_user_meta( $user_id, 'my_custom_notifications' );
                    // Prepare data to be sent back in the next heartbeat_send cycle
                    // This will be picked up by the heartbeat_send filter.
                    // We can directly modify global $data if needed, but it's cleaner
                    // to let heartbeat_send handle the output.
                    // For immediate feedback, we could add to $response, but it's not the primary mechanism.
                }
                break;
            case 'check_server_health':
                // Perform a quick server health check.
                $health_status = 'healthy'; // Replace with actual check.
                // This status will be available in the next heartbeat_send cycle.
                break;
            // Add more actions as needed
        }
    }

    // You can also use this tick to update data that will be sent in the *next* heartbeat_send.
    // For instance, if a background task completed.
    // For simplicity, we'll rely on heartbeat_send for pushing data.

    return $response;
}
add_action( 'heartbeat_tick', 'my_custom_heartbeat_tick_handler', 10, 2 );

In this heartbeat_tick handler, we check for a custom action sent from the client (e.g., ‘reset_notifications’). If detected, we perform the server-side operation. Note that the heartbeat_tick handler receives data *from* the client and returns data *to* the client’s Heartbeat response. However, for pushing dynamic data *to* the Twig template, it’s generally more idiomatic to use the heartbeat_send filter, as it directly populates the data sent to the client for rendering.

Advanced Patterns and Considerations

Heartbeat Intervals and Performance

The Heartbeat API has configurable intervals. By default, it polls every 15-60 seconds in the admin and every 60 seconds on the front-end. For intensive operations, you might want to adjust these intervals or, more importantly, implement logic to *throttle* your Heartbeat requests. You can control the Heartbeat interval using the heartbeat_settings filter.

/**
 * Adjust Heartbeat settings.
 *
 * @param array $settings The current Heartbeat settings.
 * @return array The modified Heartbeat settings.
 */
function my_custom_heartbeat_settings( $settings ) {
    // Example: Increase interval to 2 minutes (120 seconds)
    $settings['interval'] = 120;

    // Example: Disable Heartbeat on specific pages or contexts if not needed.
    // if ( is_admin() && isset( $_GET['page'] ) && $_GET['page'] === 'my-plugin-settings' ) {
    //     $settings['disabled'] = true;
    // }

    return $settings;
}
add_filter( 'heartbeat_settings', 'my_custom_heartbeat_settings' );

Be mindful of the server load generated by frequent Heartbeat requests, especially if your handlers perform complex database queries or external API calls. Consider using transients or caching to optimize data retrieval.

Security and Data Validation

Always validate and sanitize any data received from the client via Heartbeat, just as you would with any other AJAX request. Use nonces for critical operations if necessary, although Heartbeat’s inherent AJAX nature and user context provide a baseline level of security. Ensure that sensitive data is not exposed unnecessarily.

Front-End Heartbeat Initialization

By default, Heartbeat is primarily active in the WordPress admin area. To use it on the front-end, you need to enqueue the Heartbeat script and potentially initiate the connection manually. This is typically done within a theme’s functions.php or a plugin’s main file.

/**
 * Enqueue Heartbeat script and custom JS for front-end.
 */
function my_enqueue_frontend_heartbeat() {
    // Enqueue the WordPress Heartbeat script
    wp_enqueue_script( 'heartbeat' );

    // Enqueue your custom JavaScript file that handles Heartbeat events
    wp_enqueue_script(
        'my-custom-heartbeat-handler',
        get_template_directory_uri() . '/js/heartbeat-handler.js', // Adjust path as needed
        array( 'jquery', 'heartbeat' ), // Dependencies
        filemtime( get_template_directory() . '/js/heartbeat-handler.js' ), // Version based on file modification
        true // Load in footer
    );

    // Pass localized data if needed (e.g., AJAX URL, nonces)
    wp_localize_script( 'my-custom-heartbeat-handler', 'myHeartbeatConfig', array(
        'ajax_url' => admin_url( 'admin-ajax.php' ),
        // Add any other configuration variables
    ) );

    // IMPORTANT: For Heartbeat to connect on the front-end, you might need to
    // ensure the 'heartbeat_settings' filter is not disabling it, and
    // potentially call wp.heartbeat.connect() in your JS if it doesn't auto-connect.
    // The presence of wp.heartbeat.connect() call in JS is often sufficient.
}
// Only enqueue on specific front-end pages where you need Heartbeat
// Example: Add this to a page template or a conditional check.
// add_action( 'wp_enqueue_scripts', 'my_enqueue_frontend_heartbeat' );

Ensure your heartbeat-handler.js file contains the JavaScript logic described earlier, including the `wp.heartbeat.connect()` call if automatic connection isn’t guaranteed.

Conclusion

By integrating the Heartbeat API with Timber and Twig, developers can create highly dynamic and responsive WordPress experiences. The ability to push real-time data to the client and trigger server-side actions based on client pings opens up a realm of possibilities for custom dashboards, live notifications, and interactive content management. Remember to prioritize performance, security, and clear data schemas to build robust and maintainable extensions.

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

  • 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
  • Optimizing p99 database query response latency in multi-site Service Provider custom tables
  • Troubleshooting guide: Resolving memory leak spikes caused by unclosed custom database loops in custom product catalogs
  • WordPress Development Recipe: Leveraging Nullsafe operator pipelines 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 (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 (177)
  • WordPress Plugin Development (330)
  • WordPress Theme Development (357)

Recent Posts

  • 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
  • Optimizing p99 database query response latency in multi-site Service Provider custom tables

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