André Amorim

Crafting Web Experiences

//

Pro Hit Tracker

A lightweight WordPress plugin that tracks unique daily hits per post or page via the REST API, with built-in spam and bot protection.


Features

  • REST API–based tracking — hits are recorded asynchronously via a secure POST /wp-json/pht/v1/trackendpoint; no page-reload required.
  • Unique daily hits — each IP address can only register one hit per post per calendar day, preventing repeat inflation.
  • Bot & spam protection — common crawlers, scrapers and headless clients are detected by User-Agent and silently ignored.
  • Rate limiting — each IP is limited to 60 requests per hour per endpoint/post combination; excess requests return 429.
  • Origin validation — the tracking endpoint rejects requests whose Origin or Referer header does not match the site’s own domain.
  • Honeypot field — a hidden hp parameter in the request body silently discards bot-submitted forms.
  • Session-level deduplication — the frontend JS stores a sessionStorage flag after a successful track, so navigating back to the same post in the same tab never fires a second request.
  • Nonce-secured endpoint — the tracker fetches a fresh wp_rest nonce from GET /wp-json/pht/v1/noncebefore every tracking call; invalid nonces are rejected with 403.
  • Cloudflare-aware IP detection — real visitor IPs are read from HTTP_CF_CONNECTING_IP when present, so rate limits work correctly behind Cloudflare.
  • Dashboard widget — an “Top Posts by Hits” widget appears on the WordPress admin dashboard, listing the five most-viewed pieces of content.
  • Admin list columns — a sortable “Hits” column is added to the post/page list tables for all tracked post types.
  • Configurable post types — track any combination of public post types from the settings page; defaults to post and page.
  • Data reset — the settings page includes a “Reset All Hits” action that wipes all post_hits meta rows and rate-limit transients.
  • Self-hosted auto-updates — the plugin checks for new versions daily against the author’s own update hub and integrates with the standard WordPress update flow.

Installation

  1. Upload the afca-pro-hit-tracker folder to /wp-content/plugins/.
  2. Activate the plugin through Plugins → Installed Plugins.
  3. Go to Settings → Pro Hit Tracker to configure which post types to track.

Note: The vendor/ directory (Composer autoloader) must be present. If you are installing from source, run composer install first.


How It Works

Browser loads singular post/page
  └─ tracker.js is enqueued (only on singular views for tracked post types)
       └─ Fetches GET /wp-json/pht/v1/nonce  →  receives { nonce }
            └─ POSTs to /wp-json/pht/v1/track with X-WP-Nonce header
                 ├─ SpamGuard checks: bot UA, rate limit, origin/referer
                 ├─ HitRecorder checks: already counted today? (transient)
                 └─ Records hit:
                      ├─ post_hits            (post meta — all-time total)
                      └─ post_hits_daily_YYYY-MM-DD  (post meta — daily bucket)

Hit data is stored entirely in standard WordPress post meta — no custom database tables are created.


REST API Endpoints

GET /wp-json/pht/v1/nonce

Returns a short-lived wp_rest nonce for use in the tracking request.

Response:

{ "nonce": "abc123def4" }

LiteSpeed Cache no-cache headers are set automatically on this endpoint.


POST /wp-json/pht/v1/track

Records a hit for a given post.

Headers:

HeaderValue
Content-Typeapplication/json
X-WP-NonceNonce obtained from the /nonce endpoint

Body:

FieldTypeRequiredDescription
post_idintegerYesThe ID of the post/page to track
hpstringNoHoneypot field — must be empty; non-empty values are silently discarded

Responses:

StatusMeaning
200 { "status": "counted" }Hit recorded successfully
200 { "status": "already counted" }This IP already counted today
200 { "status": "bot ignored" }Request detected as a bot
200 { "status": "ok" }Honeypot triggered
403 { "error": "invalid nonce" }Nonce missing or invalid
403 { "error": "forbidden" }Origin/referer mismatch
404 { "error": "invalid post" }Post not found, not published, or not a tracked type
429 { "error": "rate limit exceeded" }Too many requests from this IP

Post Meta Keys

Meta KeyDescription
post_hitsCumulative all-time hit count (integer)
post_hits_daily_YYYY-MM-DDHit count for the given calendar day

You can query these directly with standard WordPress functions:

$total_hits = (int) get_post_meta( $post_id, 'post_hits', true );
$hits_today = (int) get_post_meta( $post_id, 'post_hits_daily_' . date( 'Y-m-d' ), true );

Settings

Navigate to Settings → Pro Hit Tracker in the WordPress admin.

SettingDefaultDescription
Tracked Post Typespost, pageComma-separated list of post type slugs to track. All registered public post types on the current site are listed as a reference.

Reset All Hits

The Danger Zone section provides a “Reset All Hits” button. Clicking it permanently deletes:

  • All post_hits and post_hits_daily_* post meta rows.
  • All hit_* deduplication transients.
  • All pht_rate_* rate-limit transients.

This action cannot be undone.


Admin Features

Dashboard Widget

Top Posts by Hits widget appears on the WordPress dashboard home screen, listing the top 5 most-viewed published posts across all tracked post types, with direct edit links. Administrators also see a quick link to the settings page.

Sortable Hits Column

Hits column is added to the post list table for every tracked post type. The column is sortable — click the header to order posts by total hit count ascending or descending.


Auto-Updates

The plugin registers a daily WP-Cron event (afca_pro_hit_tracker_updates) that polls the author’s update hub for new releases. When a newer version is available, it surfaces in the standard Plugins → Updates screen and can be updated with one click.


Project Structure

afca-pro-hit-tracker/
├── afca-pro-hit-tracker.php   # Plugin bootstrap & hook registration
├── composer.json              # PSR-4 autoload + dev dependencies
├── phpcs.xml                  # PHP CodeSniffer ruleset (WordPress standard)
├── assets/
│   └── js/
│       └── tracker.js         # Frontend tracking script
└── src/
    ├── Admin/
    │   ├── AdminColumns.php   # Hits column in post list tables
    │   ├── DashboardWidget.php# Top-posts dashboard widget
    │   ├── SettingsPage.php   # Settings & reset UI
    │   └── Updates.php        # Self-hosted auto-update logic
    ├── Api/
    │   ├── NonceEndpoint.php  # GET /pht/v1/nonce
    │   └── TrackEndpoint.php  # POST /pht/v1/track
    ├── Frontend/
    │   └── Enqueue.php        # Enqueues tracker.js on singular views
    ├── Support/
    │   ├── Helpers.php        # IP resolution, bot detection
    │   └── PostTypes.php      # Reads tracked post types from options
    └── Tracker/
        ├── Cleaner.php        # Wipes all hit data (used by reset)
        ├── HitRecorder.php    # Writes post meta & dedup transient
        └── SpamGuard.php      # Bot, rate-limit & origin checks

Development

Install dependencies:

composer install

Run code linting:

vendor/bin/phpcs --standard=phpcs.xml src/

The project follows the WordPress Coding Standards.


Published date:

Modified date: