Skip to content

Gravity Forms Entries Unread Indicator

Chris Eggleston 1 min read

Problem

Does anyone know how to add a notification badge next to the “Entries” link (backend) when a new form or entry is received?

The badge should include a counter indicating how many entries remain unopened.

When looking at the WordPress admin, there is no indicator in the sidebar menu that shows how many unread Gravity Forms entries you have. You would have to check each form to see this information or go to the Gravity Forms dashboard widget.

Other plugins and WordPress functions use this indicator to show notifications or the number of plugins that need to be updated.

Thanks to this Gravity Forms user’s request, I took some time to see if I could come up with a simple solution.

Solution

A simple WordPress plugin that enhances Gravity Forms by adding an unread entries indicator to the “Entries” menu in the WordPress admin dashboard.

It also includes an AJAX feature that dynamically marks entries as read/unread, automatically updating the unread count in real-time.

gravity-forms-entries-unread-indicator.phpGist by chriseggGitHub
<?php
/**
 * Plugin Name: Gravity Forms Unread Entries Indicator
 * Description: Adds an indicator to the Gravity Forms Entries menu showing the number of unread entries.
 * Version: 1.0
 * Author: Chris Egglelston
 * Website: https://gravityranger.com
 */

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

// Add unread entries indicator to the Entries submenu
add_action('admin_menu', 'add_unread_entries_indicator_to_entries', 999);
function add_unread_entries_indicator_to_entries() {
    // Get all forms
    $forms = GFAPI::get_forms();

    // Initialize unread count
    $unread_count = 0;

    // Loop through all forms and count unread entries
    foreach ($forms as $form) {
        $entries = GFAPI::get_entries($form['id'], array(), null, array('status' => 'active'));

        foreach ($entries as $entry) {
            if (!gform_get_meta($entry['id'], 'is_read')) {
                $unread_count++;
            }
        }
    }

    // Add the bubble to the Entries submenu
    global $submenu;
    if (isset($submenu['gf_edit_forms'])) {
        foreach ($submenu['gf_edit_forms'] as $key => $item) {
            if ($item[2] === 'gf_entries') { // "Entries" submenu slug
                $submenu['gf_edit_forms'][$key][0] .= " <span class='update-plugins count-$unread_count' style='margin-left: 5px;'>
                                                        <span class='plugin-count'>$unread_count</span>
                                                    </span>";
                break;
            }
        }
    }
}

// Mark entries as read/unread when toggled via AJAX
add_action('wp_ajax_gf_toggle_entry_read', 'update_unread_count');
function update_unread_count() {
    // Get entry ID and action from the AJAX request
    $entry_id = isset($_POST['entryId']) ? absint($_POST['entryId']) : null;
    $mark_as_read = isset($_POST['markAsRead']) ? filter_var($_POST['markAsRead'], FILTER_VALIDATE_BOOLEAN) : true;

    if (!$entry_id) {
        wp_send_json_error('No entry ID provided.');
        return;
    }

    // Update the entry's read status
    gform_update_meta($entry_id, 'is_read', $mark_as_read);

    // Recalculate unread count
    $unread_count = 0;
    $forms = GFAPI::get_forms();

    foreach ($forms as $form) {
        $entries = GFAPI::get_entries($form['id'], array(), null, array('status' => 'active'));
        foreach ($entries as $entry) {
            if (!gform_get_meta($entry['id'], 'is_read')) {
                $unread_count++;
            }
        }
    }

    // Send back the new unread count
    wp_send_json_success(array('unread_count' => $unread_count));
}

// Enqueue inline JavaScript
add_action('admin_enqueue_scripts', 'add_inline_unread_entries_script');
function add_inline_unread_entries_script() {
    // Enqueue jQuery as a dependency
    wp_enqueue_script('jquery');

    // Add inline JavaScript
    $inline_script = <<<EOT
jQuery(document).on('click', 'a[id^="mark_read_"], a[id^="mark_unread_"]', function (e) {
    e.preventDefault();

    // Extract the entry ID from the link ID
    const entryId = jQuery(this).attr('id').split('_')[2];
    const isMarkingAsRead = jQuery(this).attr('id').startsWith('mark_read');

    // Perform the AJAX request to mark the entry as read/unread
    jQuery.post(ajaxurl, {
        action: 'gf_toggle_entry_read',
        entryId: entryId,
        markAsRead: isMarkingAsRead // Pass whether we're marking it as read
    }).done(function (response) {
        if (response.success) {
            const unreadCount = response.data.unread_count;

            // Update the bubble in the menu
            const menuItem = jQuery('#toplevel_page_gf_edit_forms .plugin-count');
            if (menuItem.length) {
                menuItem.text(unreadCount);

                // Hide the bubble if there are no unread entries
                if (unreadCount === 0) {
                    menuItem.parent().hide();
                } else {
                    menuItem.parent().show();
                }
            }

            // Let Gravity Forms handle the DOM toggle for read/unread
            ToggleRead(entryId, '');
        } else {
            console.error('Error:', response.data);
        }
    }).fail(function () {
        console.error('Failed to toggle read/unread status.');
    });
});
EOT;

    wp_add_inline_script('jquery', $inline_script);
}

How to use this code

You can either use a code snippet plugin like WPCodeBox or install it like any other plugin.

  1. Code snippet plugin

Simple copy the code above, past it into your snippet plugin, and enable the code:

  1. Install via WordPress plugins

Go to the Gist file here, then click the download zip button. Once the file is downloaded head over to your WordPress admin area. Go to Plugins > Add New > Upload plugin and drop the zip file into the file selector area, then click Install Now and Activate.

Need More Help?

If you still need help, use the chat or leave a comment below and we’ll get back to you.

Comments

Ask a question or leave a comment

Your email is never shown. For help with a specific form, share what you expected and what happened instead.