• 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 Elementor custom widgets extensions utilizing modern Heartbeat API schemas

How to build custom Elementor custom widgets extensions utilizing modern Heartbeat API schemas

Leveraging WordPress Heartbeat API for Dynamic Elementor Widgets

The WordPress Heartbeat API, while often associated with auto-saves and post locking, offers a powerful, albeit underutilized, mechanism for real-time data synchronization within the Elementor editor. This allows for the creation of highly dynamic custom widgets that can update their content or behavior based on external data sources or user interactions without requiring a full page reload. This post details how to architect and implement such extensions, focusing on efficient data handling and modern API schema design.

Understanding the Heartbeat API Flow

The Heartbeat API operates on a client-server model. The browser periodically sends requests (heartbeats) to the server, and the server can respond with data or instructions. Elementor hooks into this process to manage its own editor state. We can tap into this same channel to push custom data to the Elementor editor or to trigger actions on the client-side based on server-side events.

Registering Custom Heartbeat Routes

To send custom data, we need to register new routes within the Heartbeat API. This is done using the heartbeat_send filter. It’s crucial to namespace your data to avoid conflicts with core WordPress or other plugin data. We’ll define a custom route, say my_custom_widget_data, which will carry our widget-specific information.

PHP Implementation for Heartbeat Data Registration

<?php
/**
 * Plugin Name: My Elementor Custom Widgets
 * Description: Adds custom widgets with Heartbeat API integration.
 * Version: 1.0.0
 * Author: Your Name
 */

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

/**
 * Register custom heartbeat data.
 *
 * @param array $response The response data.
 * @param array $data The incoming heartbeat data.
 * @return array Modified response data.
 */
function my_elementor_custom_widgets_heartbeat_send( $response, $data ) {
    // Check if our custom route is requested.
    if ( isset( $data['my_custom_widget_data'] ) ) {
        // Fetch or generate your dynamic data here.
        // For demonstration, let's simulate fetching product stock.
        $product_stock = rand( 10, 100 ); // Replace with actual stock retrieval logic.

        $response['my_custom_widget_data'] = array(
            'stock_level' => $product_stock,
            'last_updated' => time(),
        );
    }
    return $response;
}
add_filter( 'heartbeat_send', 'my_elementor_custom_widgets_heartor_send', 10, 2 );

/**
 * Enqueue scripts for Elementor editor.
 */
function my_elementor_custom_widgets_enqueue_editor_scripts() {
    wp_enqueue_script(
        'my-elementor-custom-widgets-editor',
        plugin_dir_url( __FILE__ ) . 'assets/js/editor-script.js',
        array( 'jquery', 'heartbeat' ), // Depend on jQuery and Heartbeat
        '1.0.0',
        true
    );
}
add_action( 'elementor/editor/after_enqueue_scripts', 'my_elementor_custom_widgets_enqueue_editor_scripts' );

In this PHP snippet:

  • We define a function my_elementor_custom_widgets_heartbeat_send that hooks into heartbeat_send.
  • Inside the function, we check if our custom key my_custom_widget_data is present in the incoming heartbeat data. This signifies that the client is interested in our data.
  • We then prepare an array with our dynamic data (e.g., stock_level) and add it to the response array under our custom key.
  • The my_elementor_custom_widgets_enqueue_editor_scripts function ensures our JavaScript file is loaded only within the Elementor editor and correctly declares dependencies on jquery and heartbeat.

Client-Side JavaScript for Data Consumption

On the client-side, within the Elementor editor, we need to listen for Heartbeat API events and process the data received. We’ll use the heartbeat-send event to request our data and the heartbeat-tick event to receive and process it.

JavaScript Implementation (editor-script.js)

(function($) {
    $(document).ready(function() {
        var editor = false;

        // Check if we are in the Elementor editor
        if (typeof elementor !== 'undefined' && elementor.isEditMode()) {
            editor = true;
        }

        if (!editor) {
            return; // Exit if not in Elementor editor
        }

        // Request custom data on heartbeat send
        $(document).on('heartbeat-send', function(e, data) {
            // Request our custom data
            data.my_custom_widget_data = true;
        });

        // Process received heartbeat data
        $(document).on('heartbeat-tick', function(e, data) {
            if (data.my_custom_widget_data) {
                var widgetData = data.my_custom_widget_data;
                console.log('Received custom widget data:', widgetData);

                // Now, update your Elementor widgets based on this data.
                // This is where you'd target specific widgets and update their content.
                // Example: Update a widget's text based on stock level.
                // You'll need to identify your widget instances.
                // For instance, if your widget has a specific CSS class or data attribute.

                // Example: Find all widgets with a specific data attribute and update them.
                // This requires your custom widget to have a way to be identified.
                // Let's assume your widget has a data-widget-id attribute.
                // You would typically find widgets using Elementor's internal API or DOM traversal.

                // A more robust approach would involve Elementor's widget API if available for dynamic updates.
                // For direct DOM manipulation (use with caution):
                $('.my-dynamic-widget[data-widget-id]').each(function() {
                    var widgetElement = $(this);
                    var widgetId = widgetElement.data('widget-id'); // Assuming your widget stores its ID

                    // Find the specific element within the widget to update
                    var stockDisplay = widgetElement.find('.stock-level-display'); // Assuming a class for stock display

                    if (stockDisplay.length && widgetData.stock_level !== undefined) {
                        stockDisplay.text('Stock: ' + widgetData.stock_level);
                        // You might also want to add classes for styling based on stock
                        if (widgetData.stock_level < 10) {
                            stockDisplay.addClass('low-stock').removeClass('in-stock');
                        } else {
                            stockDisplay.addClass('in-stock').removeClass('low-stock');
                        }
                    }
                });
            }
        });

        // Optional: Set heartbeat interval if needed, but Elementor usually manages this.
        // wp.heartbeat.interval( 15000 ); // e.g., 15 seconds
    });
})(jQuery);

In this JavaScript:

  • We first ensure the code only runs within the Elementor editor.
  • On heartbeat-send, we add our custom key my_custom_widget_data: true to the data object. This tells the server we want to receive data for this key.
  • On heartbeat-tick, we check if data.my_custom_widget_data exists. If it does, we process the received data.
  • The example demonstrates how you might find specific widgets in the DOM (using hypothetical selectors like .my-dynamic-widget[data-widget-id]) and update their content (e.g., a .stock-level-display element) based on the received stock_level.
  • Important: The DOM manipulation part is a simplified example. For robust solutions, you’d ideally interact with Elementor’s widget rendering API if it provides hooks for dynamic content updates. Otherwise, careful DOM traversal and manipulation are required, ensuring your selectors are specific and resilient to Elementor’s internal DOM structure changes.

Creating the Custom Elementor Widget

Now, let’s define a basic Elementor widget that can display this dynamic data. This widget will need a placeholder element in its template that our JavaScript can target.

PHP Widget Class

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

class My_Dynamic_Stock_Widget extends \Elementor\Widget_Base {

    public function get_name() {
        return 'my-dynamic-stock-widget';
    }

    public function get_title() {
        return esc_html__( 'Dynamic Stock Widget', 'my-elementor-custom-widgets' );
    }

    public function get_icon() {
        return 'eicon-cart'; // Elementor icon class
    }

    public function get_categories() {
        return array( 'my-custom-widgets' ); // Custom category
    }

    protected function _register_controls() {
        $this->start_controls_section(
            'content_section',
            array(
                'label' => esc_html__( 'Content', 'my-elementor-custom-widgets' ),
                'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
            )
        );

        $this->add_control(
            'stock_label',
            array(
                'label' => esc_html__( 'Stock Label', 'my-elementor-custom-widgets' ),
                'type' => \Elementor\Controls_Manager::TEXT,
                'default' => esc_html__( 'Current Stock:', 'my-elementor-custom-widgets' ),
                'placeholder' => esc_html__( 'Enter your stock label', 'my-elementor-custom-widgets' ),
            )
        );

        $this->end_controls_section();
    }

    protected function render() {
        $settings = $this->get_settings_for_display();
        $stock_label = $settings['stock_label'];

        // The data will be populated by JavaScript in the editor.
        // For the frontend render, you might fetch data directly or use a placeholder.
        // For simplicity, we'll use a placeholder here and rely on JS for editor preview.
        // On the frontend, you'd typically fetch this data via AJAX or a separate Heartbeat call if needed.
        ?>
        <div class="my-dynamic-widget" data-widget-id="get_id() ); ?>">
            <span class="stock-label"><?php echo esc_html( $stock_label ); ?></?php echo esc_html( $stock_label ); ?></span>
            <span class="stock-level-display">Loading stock...</span>
        </div>
        <?php
    }

    protected function _content_template() {
        // This template is used for the Elementor editor preview.
        // It will be rendered using JavaScript and can directly access data
        // that the Heartbeat API pushes to the client.
        ?>
        <div class="my-dynamic-widget" data-widget-id="<%= getId() %>">
            <span class="stock-label"><%= getSettings('stock_label') %></span>
            <span class="stock-level-display">Loading stock...</span>
        </div>
        <?php
    }

    // Ensure the widget is registered. This would typically be in your main plugin file.
    // public function __construct( array $data = [], array $args = null ) {
    //     parent::__construct( $data, $args );
    //     // Register widget scripts/styles if needed
    //     wp_register_script( 'my-elementor-custom-widgets-editor', plugin_dir_url( __FILE__ ) . 'assets/js/editor-script.js', array( 'jquery', 'heartbeat' ), '1.0.0', true );
    // }
}

In this widget class:

  • We define the widget’s name, title, icon, and category.
  • The _register_controls method sets up a simple text control for the stock label.
  • The render method generates the HTML for the frontend. It includes a data-widget-id attribute for JavaScript targeting and a stock-level-display span where the stock will be shown.
  • The _content_template method is crucial for the Elementor editor. It uses Underscore.js templating syntax (e.g., <%= ... %>) to render the widget’s structure. This template is what the JavaScript will interact with to update the display.
  • The data-widget-id attribute is dynamically set using <%= getId() %> in the template, which is essential for our JavaScript to target specific widget instances.

Integrating the Widget and Scripts

To make this work, ensure:

  • Your PHP widget class is correctly registered with Elementor. This usually involves hooking into elementor/widgets/widgets_registered.
  • The editor-script.js file is enqueued for the Elementor editor, as shown in the PHP Heartbeat registration section.
  • The Heartbeat API registration function is also included in your plugin’s main file or an included file.

Registering the Widget

<?php
// In your main plugin file (e.g., my-elementor-custom-widgets.php)

// ... (previous Heartbeat and enqueue code) ...

use Elementor\Plugin;

class My_Elementor_Custom_Widgets_Plugin {

    public function __construct() {
        add_action( 'elementor/widgets/widgets_registered', array( $this, 'register_widgets' ) );
        // Ensure Elementor is active before trying to register widgets
        add_action( 'plugins_loaded', array( $this, 'init' ) );
    }

    public function init() {
        // Add custom widget category
        add_action( 'elementor/elements_categories_registered', array( $this, 'add_elementor_category' ) );
    }

    public function add_elementor_category( $elements_manager ) {
        $elements_manager->add_category(
            'my-custom-widgets',
            array(
                'title' => esc_html__( 'My Custom Widgets', 'my-elementor-custom-widgets' ),
            )
        );
    }

    public function register_widgets() {
        // Include the widget file
        require_once( __DIR__ . '/widgets/my-dynamic-stock-widget.php' );

        // Register the widget
        Plugin::instance()->widgets_manager->register_widget_type( new My_Dynamic_Stock_Widget() );
    }
}

// Instantiate the plugin
new My_Elementor_Custom_Widgets_Plugin();

This setup ensures that your custom widget is recognized by Elementor and placed into a dedicated category. The init method with plugins_loaded hook is a standard practice to ensure Elementor is ready before attempting to add categories or widgets.

Advanced Considerations and Best Practices

  • Data Schema Design: For complex data, consider a JSON schema for your Heartbeat data. This makes parsing and validation on the client-side more predictable.
  • Performance: Heartbeat requests can increase server load. Optimize your server-side data fetching. Cache data where possible. Consider adjusting the heartbeat interval if frequent updates aren’t strictly necessary (though Elementor often manages this intelligently).
  • Error Handling: Implement robust error handling in both PHP and JavaScript. Log errors server-side and provide user-friendly feedback client-side if data fails to load or update.
  • Security: Always sanitize and validate data. Use nonces for critical operations if your Heartbeat data triggers server-side actions beyond simple data retrieval.
  • Frontend vs. Editor: Remember that the Heartbeat API primarily synchronizes data within the Elementor editor. For live frontend updates, you’ll typically need AJAX, WebSockets, or a different approach. However, data fetched via Heartbeat in the editor can inform the initial render of the widget on the frontend if you choose to pass it along or re-fetch it.
  • Elementor API: Explore Elementor’s JavaScript API for more integrated ways to update widget content rather than direct DOM manipulation. This can lead to more stable and future-proof extensions.

By integrating the WordPress Heartbeat API with custom Elementor widgets, you can create highly interactive and dynamic editing experiences. This approach allows for real-time feedback and data synchronization, enhancing the usability and power of your custom Elementor extensions for e-commerce and beyond.

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 build custom WooCommerce core overrides extensions utilizing modern Transients API schemas
  • Step-by-Step Guide to building a custom broken link checker block for Gutenberg using REST API custom routes
  • How to build custom Understrap styling structures extensions utilizing modern REST API Controllers schemas
  • Troubleshooting WP_DEBUG notice floods in production when using modern Genesis child themes wrappers
  • Implementing automated compliance reporting for custom hospital clinic appointments ledgers using dompdf library

Categories

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

Recent Posts

  • How to build custom WooCommerce core overrides extensions utilizing modern Transients API schemas
  • Step-by-Step Guide to building a custom broken link checker block for Gutenberg using REST API custom routes
  • How to build custom Understrap styling structures extensions utilizing modern REST API Controllers schemas

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (841)
  • Debugging & Troubleshooting (637)
  • Security & Compliance (616)
  • 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