Wo WooCommerce Intermediate

DataFirefly Live Counters

Complete WordPress/WooCommerce plugin documentation: installation, settings, available counters, time windows and goals, cache architecture, developer API.

Updated Module version 1.1.1

DataFirefly Live Counters displays animated counters (customers, orders, social followers, custom KPIs) on your WordPress/WooCommerce site that stay accurate even when the entire site is served from a full-page cache like LiteSpeed Cache or WP Rocket.

Installation and quick start

Prerequisites

  • WordPress 6.2 or above (tested on 6.7).
  • PHP 8.1 or above.
  • WooCommerce 7.0+ recommended for store counters. Without WooCommerce, social and custom KPI counters stay fully functional.
  • Polylang or WPML optional for multilingual labels.

Installation

  1. Download dflivecounters.zip from your DataFirefly account.
  2. In WordPress, go to Plugins → Add New → Upload Plugin.
  3. Choose the zip and click Install Now.
  4. Activate the plugin. A new Live Counters item appears under WooCommerce (or Settings if WooCommerce isn’t installed).

First display in 30 seconds

Drop this shortcode into any page or post:

[dflivecounters]

On first load, a grid of four counters appears with a count-up animation. Numbers are computed from your WooCommerce catalog and cached.

General settings

Go to WooCommerce → Live Counters. The page has four cards, followed by a live preview and a cache-flush button.

“Display & cache” card

  • Style: Cards, Minimal, Gradient.
  • Columns: 1 to 6. Responsive: 2 columns on mobile, 1 on very small screens.
  • Accent color: used for icons, numbers (cards) and background (gradient). Default #0f172a.
  • Animation duration (ms): 200 to 8,000. 0 disables animation.
  • Counter cache (min): 60 by default.
  • Social cache (min): 360 by default (social APIs are rate-limited).
  • Abbreviate large numbers: displays 12.4k instead of 12,400.
  • Add “+” to cumulative counters.
  • Pre-warm cache automatically (cron): Action Scheduler preferred, WP-Cron fallback.

Counted order statuses

  • Counted statuses (customers, orders, items, countries): defaults to Processing and Completed.
  • “Shipped” statuses: used only for Products shipped. Defaults to Completed.

Activity start date

The Years in business counter is computed from the date set in “Founding date”.

Clear and rebuild cache

The “↻ Clear and rebuild cache now” button removes all plugin transients and triggers an immediate warm-up. Any settings change automatically flushes the counter cache and reschedules the warm-up.

WooCommerce counters

Available counters

  • Customers served (customers): distinct billing emails on orders in a counted status.
  • Products shipped (shipped): sum of item quantities on orders in a “shipped” status.
  • Orders processed (orders).
  • Items sold (items_sold): sum of quantities across all order line items.
  • Products in catalog (products).
  • Customer reviews (reviews): approved reviews.
  • Countries shipped to (countries).
  • Years in business (years): from the founding date.

Enable and customize a counter

In the “Store counters” table, tick Active and optionally:

  • Set a custom label.
  • Choose a time window (see dedicated section).
  • Add an offset to integrate older history (e.g. 1,200 customers from a previous store).
  • Set a goal to activate the progress bar.

HPOS compatibility

The plugin auto-detects HPOS (High-Performance Order Storage) or legacy (CPT) storage. Queries are written in two optimized flavors. HPOS and Cart/Checkout Blocks compatibility is declared via the before_woocommerce_init hook.

Social and custom KPI counters

Supported social networks

  • Facebook and Instagram — automatic retrieval via the Meta Graph API v19 (Instagram for Business or Creator accounts only).
  • TikTok, X (Twitter), LinkedIn, YouTube — manual entry.

TikTok, X and LinkedIn don’t expose a follower counter through a reliable public API, hence the manual entry.

Configure Facebook or Instagram via the Meta Graph API

  1. Create an app at developers.facebook.com.
  2. Generate a long-lived access token with the pages_read_engagement permission (Facebook) or instagram_basic + pages_show_list (Instagram).
  3. Get the Facebook Page ID or IG Business ID.
  4. In the “Social networks” card, tick “Fetch via API”, paste the ID into Object ID and the token into Access token.

If the API call fails (expired token, rate limit), the plugin keeps the last known value. The “manual” field serves as the ultimate fallback.

Custom KPI counters

In the “Custom KPI counters” card, click “+ Add counter”, then fill: icon (users, award, heart, leaf, download…), label, value, optional prefix (“$”, “+”), optional suffix (“%, h, M”), optional goal.

Time windows, goals and trend

Time windows per counter

Counters that aggregate over time (customers, shipped, orders, items_sold, reviews, countries) can be restricted:

  • All-time: default behavior.
  • This year: since January 1st.
  • This month: since the 1st of the month.
  • Last 30 days: rolling window.

The effect “124 orders this month” is often more engaging than “9,421 orders”.

Goals and progress bar

Setting a goal in the “Goal (0 = none)” column automatically activates a bar under the counter, animated alongside the count-up, up to min(100%, value / goal). Also available on social and custom counters.

Trend indicator ▲/▼

A colored chip appears next to the number:

  • ▲ green if the value increased since the previous snapshot.
  • ▼ red if it decreased.
  • No chip if the change is null or history is insufficient.

The percentage is computed on a 7-day rolling window by default, configurable via the dflc_trend_window filter. Baselines are stored in a single WordPress option (dflc_trend).

Expected patience. On a new site, the trend chip only appears after the window has elapsed (7 days by default).

Display: block, widget, shortcode

Gutenberg block

In the block editor, search for DataFirefly Live Counters (Widgets category). The inspector panel lets you configure columns, style and the list of counters to display. The preview uses ServerSideRender, identical to the front render.

Classic widget

Under Appearance → Widgets, add “DataFirefly Live Counters”. Fields: title, columns (0 to 6), style, keys (comma-separated list, empty = all enabled counters).

Shortcode

[dflivecounters]
[dflivecounters keys="customers,orders,reviews" columns="3"]
[dflivecounters keys="social_facebook,social_instagram" columns="2" style="gradient"]
[dflivecounters keys="custom_0,custom_1" style="minimal"]

Supported attributes: keys (string, key list), columns (int 1-6), style (cards, minimal, gradient).

Available keys

Counter Key
Customers customers
Products shipped shipped
Orders processed orders
Items sold items_sold
Products in catalog products
Customer reviews reviews
Countries shipped to countries
Years in business years
Social networks social_facebook, social_instagram, social_tiktok, social_twitter, social_linkedin, social_youtube
Custom counters custom_0, custom_1, etc.

Theme insertion (PHP)

echo do_shortcode( '[dflivecounters keys="customers,orders" columns="2"]' );

Cache architecture

The problem

When a page cache (LiteSpeed, WP Rocket, NGINX micro-cache, Varnish, Cloudflare APO) serves pre-generated HTML, any number rendered in PHP is frozen. The classic answer — disabling the cache on these pages — seriously hurts performance.

The principle: separate structure and values

  • Cacheable structure: grid, icons, labels and empty slots, server-rendered, perfectly cacheable.
  • Non-cacheable values: fetched via fetch() to a dedicated REST route with a short Cache-Control header.

The visitor receives the cached HTML instantly, then numbers fill in JavaScript with a count-up animation.

Transient cache + warm-up

The REST route never runs a heavy SQL query during a visit. It reads WordPress transients, pre-warmed by Action Scheduler (dflc_warm_cache job) or WP-Cron as fallback.

Stale-while-revalidate

If a transient expires right between two warm-ups:

  1. The last known value is read from the persistent option dflc_lastgood (which survives transient expiration) and returned immediately.
  2. An asynchronous refresh job is queued.
  3. A short lock (2 minutes) prevents stacking concurrent refreshes.

True cold start only happens at the very first display after installation.

REST endpoint security

  • Public read-only.
  • Key whitelist: only keys matching actually configured counters are accepted.
  • Cache-Control: public, max-age=... header sized on the counter TTL.

Caveat. If your CDN ignores the Cache-Control on the REST route and caches it aggressively, numbers will be frozen at the CDN level. Exclude /wp-json/dflivecounters/v1/counters from your CDN cache if you observe this.

Developer API

Five PHP filters extend the plugin without touching the core.

dflc_counter_definitions

Add, reorder or hide counters.

add_filter( 'dflc_counter_definitions', static function ( array $items, array $settings ) {
    $items[] = array(
        'key'        => 'newsletter_subscribers',
        'label'      => 'Newsletter subscribers',
        'icon'       => 'heart',
        'suffix'     => '+',
        'prefix'     => '',
        'abbreviate' => true,
        'goal'       => 5000,
    );
    return $items;
}, 10, 2 );

dflc_compute

Short-circuits the calculation. Returning an integer takes over, null lets the core handle it.

add_filter( 'dflc_compute', static function ( $pre, string $key, array $settings ) {
    if ( 'newsletter_subscribers' === $key ) {
        return (int) get_option( 'my_newsletter_count', 0 );
    }
    return $pre;
}, 10, 3 );

dflc_counter_value

Filters the final value just before sending to the front.

add_filter( 'dflc_counter_value', static function ( int $value, string $key ) {
    if ( 'customers' === $key && $value < 1000 ) {
        return 1000;
    }
    return $value;
}, 10, 2 );

dflc_payload

Filters the entire REST payload.

add_filter( 'dflc_payload', static function ( array $payload, array $only, bool $force ) {
    foreach ( $payload as &$item ) {
        $item['emoji'] = '🎉';
    }
    return $payload;
}, 10, 3 );

dflc_trend_window

Changes the trend rolling window. Value in seconds, default 7 * DAY_IN_SECONDS.

add_filter( 'dflc_trend_window', static fn() => 30 * DAY_IN_SECONDS );

Recipe: Mailchimp counter

add_filter( 'dflc_counter_definitions', static function ( array $items ) {
    $items[] = array(
        'key' => 'mailchimp_subs', 'label' => 'Newsletter subscribers',
        'icon' => 'heart', 'suffix' => '+', 'prefix' => '',
        'abbreviate' => true, 'goal' => 0,
    );
    return $items;
} );

add_filter( 'dflc_compute', static function ( $pre, string $key ) {
    if ( 'mailchimp_subs' !== $key ) {
        return $pre;
    }
    $response = wp_remote_get( 'https://us1.api.mailchimp.com/3.0/lists/LIST_ID', array(
        'headers' => array( 'Authorization' => 'Bearer ' . MAILCHIMP_API_KEY ),
    ) );
    if ( is_wp_error( $response ) ) {
        return 0;
    }
    $body = json_decode( wp_remote_retrieve_body( $response ), true );
    return (int) ( $body['stats']['member_count'] ?? 0 );
}, 10, 2 );

Troubleshooting

Numbers don't animate

  • Verify that dflc-front.js loads (browser network tab).
  • Verify the REST route /wp-json/dflivecounters/v1/counters answers with 200 and valid JSON.
  • Test with another theme.

Numbers always display "—"

  • The REST call failed. Check the JS console.
  • The REST route may be blocked by a security plugin.

Numbers don't update

  • Check that "Pre-warm cache automatically" is enabled.
  • On low-traffic sites, consider a real system cron instead of WP-Cron.
  • Force a refresh via the "↻ Clear and rebuild cache now" button.

Meta API call returns 0

  • Verify token validity on the Access Token Debugger.
  • Verify the Instagram account is Business or Creator.

WP 6.7 "_load_textdomain_just_in_time" notice

Fixed in version 1.1.1.

Was this page helpful?

Still stuck? Contact support