• 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 Carbon Fields custom wrappers extensions utilizing modern Heartbeat API schemas

How to build custom Carbon Fields custom wrappers extensions utilizing modern Heartbeat API schemas

Leveraging Carbon Fields for Custom Wrapper Extensions with the Heartbeat API

Carbon Fields, a powerful framework for WordPress meta boxes, options pages, and custom tables, offers extensibility through its field types and, more importantly, its wrapper classes. This post details how to build custom wrapper extensions for Carbon Fields, specifically focusing on integrating with the WordPress Heartbeat API to enable real-time data synchronization and dynamic UI updates within your custom meta boxes. This approach is invaluable for complex forms that require live feedback or periodic data refreshes without full page reloads.

Understanding Carbon Fields Wrappers

Carbon Fields utilizes wrapper classes to define the HTML structure and behavior of its fields. By default, it provides wrappers for standard HTML elements like `div`, `span`, and `label`. However, for advanced use cases, you can create custom wrappers to inject specific attributes, classes, or even custom HTML structures around your fields. This is particularly useful when you need to hook into WordPress’s AJAX mechanisms, such as the Heartbeat API.

The WordPress Heartbeat API: A Primer

The Heartbeat API is a WordPress feature that allows for frequent, short AJAX requests between the browser and the server. These requests can be used to send data to the server, receive data back, and trigger actions. It’s commonly used for autosave functionality, post locking, and real-time notifications. The API operates on a schedule, sending requests at intervals defined by WordPress or plugins. We can hook into this by registering custom Heartbeat callbacks.

Designing a Custom Wrapper for Heartbeat Integration

Our goal is to create a custom Carbon Fields wrapper that, when applied to a field, will automatically enqueue a JavaScript file. This JavaScript file will then establish a connection with the Heartbeat API, sending data from our field and potentially updating it based on server responses. This is ideal for fields that display dynamic information, such as a post’s revision count, a user’s online status, or a custom counter that increments periodically.

Step 1: Registering the Custom Wrapper Class

First, we need to define our custom wrapper class. This class will extend `Carbon_Fields\Field\Wrapper\Wrapper` and will be responsible for enqueueing our JavaScript asset. We’ll register this wrapper using the `carbon_fields_register_wrapper` hook.

Custom Wrapper Class Definition

Create a file, for example, inc/wrappers/heartbeat_wrapper.php within your plugin or theme. This file will contain the following PHP code:

<?php
/**
 * Custom Carbon Fields wrapper for Heartbeat API integration.
 */

use Carbon_Fields\Field\Wrapper\Wrapper;

class Heartbeat_Field_Wrapper extends Wrapper {

    /**
     * Get the name of the wrapper.
     *
     * @return string
     */
    public static function get_name() {
        return 'heartbeat_wrapper';
    }

    /**
     * Enqueue necessary assets for the wrapper.
     */
    public static function enqueue_assets() {
        // Enqueue our custom JavaScript file.
        wp_enqueue_script(
            'carbon-fields-heartbeat-wrapper',
            plugin_dir_url( __FILE__ ) . '../assets/js/heartbeat-wrapper.js', // Adjust path as needed
            array( 'jquery', 'heartbeat' ), // Depend on jQuery and Heartbeat API
            filemtime( plugin_dir_path( __FILE__ ) . '../assets/js/heartbeat-wrapper.js' ) // Cache busting
        );
    }

    /**
     * Render the wrapper HTML.
     *
     * @param array $attributes Attributes for the wrapper element.
     * @param string $content    The field's rendered HTML content.
     */
    public static function render( $attributes, $content ) {
        // Add a custom class for JavaScript targeting.
        $attributes['class'] = ( isset( $attributes['class'] ) ? $attributes['class'] . ' ' : '' ) . 'carbon-field-heartbeat-wrapper';

        // Render the wrapper with custom attributes.
        return static::render_html( 'div', $attributes, $content );
    }
}

Registering the Wrapper

In your main plugin file or functions.php, register this wrapper:

add_action( 'carbon_fields_register_wrapper', function() {
    require_once plugin_dir_path( __FILE__ ) . 'inc/wrappers/heartbeat_wrapper.php'; // Adjust path as needed
    Carbon_Fields\Field\Field::register_wrapper( 'Heartbeat_Field_Wrapper' );
} );

Step 2: Implementing the Heartbeat Integration JavaScript

Now, create the JavaScript file inc/assets/js/heartbeat-wrapper.js. This script will listen for Heartbeat API events and interact with our custom wrapper’s elements.

jQuery( function( $ ) {
    // Ensure Heartbeat is available
    if ( typeof wp === 'undefined' || typeof wp.heartbeat === 'undefined' ) {
        return;
    }

    var heartbeat = wp.heartbeat;

    // Define a namespace for our Heartbeat data
    var heartbeatNamespace = 'my_custom_plugin_heartbeat';

    // Hook into the heartbeat-send event
    heartbeat.connect( heartbeatNamespace, {
        // Data to send to the server on each heartbeat
        // This could be the value of a specific field, or other context
        // For demonstration, we'll send a dummy value.
        // In a real scenario, you'd likely get this from a data attribute or input value.
        'some_data': 'initial_value'
    } );

    // Hook into the heartbeat-tick event (when data is received from the server)
    heartbeat.on( 'tick', function( event, data ) {
        // Check if our namespace is present in the response
        if ( data[heartbeatNamespace] ) {
            var serverData = data[heartbeatNamespace];

            // Example: Update a field's value or display based on server response
            // We need to identify the specific field. This requires careful DOM traversal
            // or passing an identifier from PHP to the JS.
            // For simplicity, let's assume we have a field with a specific ID.
            // In a real application, you'd likely use data attributes set by the wrapper.

            // Example: Find an element with class 'carbon-field-heartbeat-wrapper'
            // and update its content. This is a simplified example.
            $( '.carbon-field-heartbeat-wrapper' ).each( function() {
                var $wrapper = $( this );
                var fieldId = $wrapper.data('field-id'); // Assuming field ID is passed via data attribute

                if ( serverData.hasOwnProperty( fieldId ) ) {
                    // Update the content of the wrapper or a specific element within it.
                    // This might involve updating a hidden input, a span, etc.
                    // For this example, let's just log it.
                    console.log( 'Heartbeat received for field ' + fieldId + ': ', serverData[fieldId] );

                    // Example: If you have a span to display the value:
                    // $wrapper.find('.heartbeat-display').text(serverData[fieldId]);
                }
            } );
        }
    } );

    // Hook into the heartbeat-error event
    heartbeat.on( 'error', function( event, data ) {
        console.error( 'Heartbeat API error:', data );
    } );

    // Hook into the heartbeat-connection-lost event
    heartbeat.on( 'connection-lost', function( event, data ) {
        console.warn( 'Heartbeat connection lost.' );
    } );

    // You might also want to send data *from* the field when it changes.
    // This would involve adding event listeners to your input fields.
    // For example, if your wrapper contains an input with class 'heartbeat-input':
    $( '.carbon-field-heartbeat-wrapper .heartbeat-input' ).on( 'change input', function() {
        var $input = $( this );
        var fieldId = $input.closest('.carbon-field-heartbeat-wrapper').data('field-id');
        var newValue = $input.val();

        // Update the data being sent to the server for the next heartbeat
        heartbeat.send( heartbeatNamespace, {
            'field_updates': {
                [fieldId]: newValue
            }
        } );
    } );
} );

Step 3: Integrating with the Server-Side (PHP)

The JavaScript needs to communicate with the server. We’ll use the `heartbeat_received` filter to process incoming Heartbeat data and the `heartbeat_send` filter to send data back to the client.

Processing Incoming Heartbeat Data

This function will be triggered by the Heartbeat API. It receives the data sent from the client and can return data to be sent back.

add_filter( 'heartbeat_received', function( $response, $data ) {
    // Check if our custom namespace is present in the incoming data
    if ( isset( $data['my_custom_plugin_heartbeat'] ) ) {
        $client_data = $data['my_custom_plugin_heartbeat'];

        // Process data sent from the client (e.g., field updates)
        if ( isset( $client_data['field_updates'] ) ) {
            $field_updates = $client_data['field_updates'];
            // In a real scenario, you would save these updates to post meta, options, etc.
            // For demonstration, we'll just log them.
            error_log( 'Received field updates via Heartbeat: ' . print_r( $field_updates, true ) );

            // Example: Update post meta for a specific post ID
            // if ( isset( $_POST['post_id'] ) ) {
            //     $post_id = intval( $_POST['post_id'] );
            //     foreach ( $field_updates as $field_key => $value ) {
            //         update_post_meta( $post_id, '_' . $field_key, sanitize_text_field( $value ) );
            //     }
            // }
        }

        // Prepare data to send back to the client
        // This data will be available in the 'tick' event in JavaScript.
        $response['my_custom_plugin_heartbeat'] = array();

        // Example: Fetch and send some dynamic data back
        // For instance, the number of revisions for the current post.
        if ( isset( $_POST['post_id'] ) ) {
            $post_id = intval( $_POST['post_id'] );
            $revisions = wp_count_post_revisions( $post_id );
            $response['my_custom_plugin_heartbeat']['post_revision_count'] = $revisions;

            // You could also fetch data from other sources or perform calculations.
            // Example: A simple counter that increments on each tick
            // $current_counter = get_option('my_heartbeat_counter', 0);
            // $response['my_custom_plugin_heartbeat']['server_counter'] = $current_counter + 1;
            // update_option('my_heartbeat_counter', $current_counter + 1);
        }
    }

    return $response;
}, 10, 2 );

Sending Data to the Heartbeat API

The `heartbeat_send` filter allows you to add data to the Heartbeat request *before* it’s sent to the server. This is useful for sending context like the current post ID.

add_filter( 'heartbeat_send', function( $send, $data ) {
    // Add context data to the heartbeat request.
    // This data will be available in $_POST['data'] on the server.
    if ( is_admin() && isset( $_POST['query']['post_id'] ) ) {
        $send['my_custom_plugin_heartbeat']['post_id'] = intval( $_POST['query']['post_id'] );
    } elseif ( is_admin() && isset( $_GET['post'] ) ) { // For older WP versions or different contexts
        $send['my_custom_plugin_heartbeat']['post_id'] = intval( $_GET['post'] );
    }
    // You can also send specific field values if needed, though often this is handled by JS.
    // $send['my_custom_plugin_heartbeat']['some_field_value'] = carbon_get_post_meta( get_the_ID(), 'my_field_key' );

    return $send;
}, 10, 2 );

Step 4: Applying the Custom Wrapper to a Carbon Field

Now, when defining your Carbon Fields, you can apply the custom wrapper. This is done using the `add_wrapper()` method.

use Carbon_Fields\Container;
use Carbon_Fields\Field;

add_action( 'carbon_fields_container_register', function() {
    Container::make( 'post_meta', __( 'Heartbeat Integration Settings', 'your-text-domain' ) )
        ->add_fields( array(
            Field::make( 'text', 'my_text_field', __( 'My Text Field', 'your-text-domain' ) )
                ->set_attribute( 'placeholder', 'Type something...' )
                // Apply the custom wrapper
                ->add_wrapper( 'heartbeat_wrapper', array(
                    'data-field-id' => 'my_text_field', // Pass an identifier for JS
                    'class' => 'my-custom-field-class' // Additional classes
                ) ),

            Field::make( 'html', 'heartbeat_display_field', __( 'Live Revision Count', 'your-text-domain' ) )
                ->set_html( '<p>Post Revisions: <span class="heartbeat-display">Loading...</span></p>' )
                // Apply the custom wrapper to a field that will display Heartbeat data
                ->add_wrapper( 'heartbeat_wrapper', array(
                    'data-field-id' => 'post_revision_count', // Match the key sent from PHP
                    'class' => 'heartbeat-display-wrapper'
                ) ),

            // Example of a field that sends data back
            Field::make( 'number', 'my_counter_field', __( 'My Counter', 'your-text-domain' ) )
                ->set_attribute( 'class', 'heartbeat-input' ) // Add class for JS event binding
                ->add_wrapper( 'heartbeat_wrapper', array(
                    'data-field-id' => 'my_counter_field',
                ) ),
        ) );
} );

Refinements and Advanced Considerations

Data Serialization: For complex data structures, consider JSON encoding/decoding. The Heartbeat API can handle JSON, but ensure your PHP and JavaScript are consistent.

Field Identification: The JavaScript needs a reliable way to identify which field it’s interacting with. Using data-field-id attributes set in PHP and read in JavaScript is a robust method. Ensure these IDs match the keys used in your Heartbeat data arrays.

Heartbeat Intervals: The default Heartbeat interval can be adjusted using the heartbeat_settings filter. For performance-critical applications, consider increasing the interval or disabling Heartbeat for certain screens where it’s not needed.

Error Handling and UI Feedback: Implement clear visual feedback for users when the Heartbeat connection is lost or errors occur. This might involve disabling input fields or displaying warning messages.

Security: Always sanitize and validate data received via the Heartbeat API, just as you would with any other form submission. Use WordPress nonces if you implement custom AJAX endpoints triggered by Heartbeat events.

Performance: Be mindful of the amount of data being sent and processed. Excessive data or complex server-side operations within the Heartbeat callbacks can lead to performance degradation. Profile your Heartbeat requests to identify bottlenecks.

Conclusion

By creating custom Carbon Fields wrappers and integrating with the WordPress Heartbeat API, you can build highly dynamic and responsive user interfaces within your WordPress administration area. This allows for real-time data updates, live feedback, and more sophisticated user experiences, all while leveraging the power and flexibility of Carbon Fields.

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 Guide: Diagnosing PHP-FPM child process pool exhaustion in multi-site network environments with modern tools
  • Debugging and Resolving complex namespace class loading collisions issues during heavy concurrent database traffic
  • Step-by-Step Guide: Offloading high-frequency customer support tickets metadata writes to a Redis KV store
  • How to refactor legacy event ticket registers queries using modern WP_Query and custom Transient caching
  • Step-by-Step Guide: Offloading high-frequency member profile directories metadata writes to a Redis KV store

Categories

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

Recent Posts

  • Debugging Guide: Diagnosing PHP-FPM child process pool exhaustion in multi-site network environments with modern tools
  • Debugging and Resolving complex namespace class loading collisions issues during heavy concurrent database traffic
  • Step-by-Step Guide: Offloading high-frequency customer support tickets metadata writes to a Redis KV store

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (873)
  • WordPress Plugin Development (726)
  • Debugging & Troubleshooting (662)
  • Security & Compliance (647)
  • SEO & Growth (492)

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