=== PBJ Analytics ===
Contributors: pbj
Tags: analytics, statistics, privacy, pageviews, dashboard, funnels, utm, sessions
Requires at least: 5.8
Tested up to: 6.7
Requires PHP: 7.4
Stable tag: 1.5.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Self-contained, privacy-friendly website analytics that lives entirely inside WordPress. No third-party services, no external scripts.

== Description ==

PBJ Analytics records every signal you'd actually open analytics to look at — pageviews, sessions, navigation paths, entry and exit pages, time on page, scroll depth, referrers (with full URL, UTM tags, and channel classification), internal site search, outbound clicks, 404s, regions and cities, languages, screen sizes, new vs returning visitors, funnels, goals, and bot/AI-crawler activity — into your own WordPress database and displays it on a charted admin dashboard. Nothing is sent to Google Analytics or any external service. Tracking uses a tiny first-party JavaScript beacon so it keeps working even when pages are served from a full-page cache.

Visitor counting is cookieless: a daily-rotated, salted hash of IP + user agent identifies unique visitors without storing any personal identifier and without setting cookies. A separate longer-rotated hash (settings-gated, toggleable for stricter privacy) tags hits as new vs returning. Bots and AI crawlers (which rarely run JS) are recorded server-side into their own dimensions so they never inflate human totals.

Bonus features: a live last-5-minutes panel, period-vs-period KPI comparisons, per-page drill-down, CSV export of any breakdown, an optional weekly email digest via wp_mail, and an optional read-only public dashboard at a tokenized URL.

== Installation ==

1. Upload pbj-analytics.zip via Plugins -> Add New -> Upload Plugin.
2. Activate.
3. View reports at Analytics in the admin sidebar; configure at Analytics -> Settings.

Settings carry over on upgrades.

== Upgrade Notice ==

= 1.2.1 =
Fixes "Avg. time on site" (and bounce rate / pages-per-session) always showing zero whenever the selected range was longer than the data on hand — which, with the default 30-day view, was almost always. No schema change; just reinstall/upgrade.

= 1.2.0 =
Major feature release. Adds sessions, navigation paths, entry/exit pages, time on page, scroll depth, UTM tracking, channel classification, internal site search, outbound clicks, 404 tracking, regions/cities, languages, screen sizes, new-vs-returning visitors, funnels, goals, period-vs-period KPI comparisons, per-page drill-down, live last-5-minutes panel, CSV export, weekly email digest, and a public read-only dashboard. Schema upgraded automatically on activation (db version 2 -> 3). Existing settings are preserved.

= 1.1.0 =
Adds separate bot and AI-crawler analytics (recorded server-side) and fixes the oversized traffic chart. Schema upgraded automatically on activation.

= 1.0.0 =
Initial release.

== Changelog ==

= 1.5.0 =
* **Guided admin.** Every admin screen now explains itself in plain English. The Settings page opens with a live "Setup checklist" card: front-end tracking status (always active on public pages — with whether logged-in users are counted), weekly email digest on/off with its recipient (optional), public dashboard on/off with its tokenized URL when enabled (optional), and funnels/goals defined (optional) — each row linking to its section below.
* **Dashboard help.** An intro line explains the period pills and the vs-previous-period KPI deltas, and a collapsible "What do these numbers mean?" legend defines sessions (30-minute window), bounce rate (single-page sessions), pages/session, avg. time on page, goal completions, entry/exit pages, and new vs returning.
* **Live page help.** The Live panel now explains it shows a rolling last-5-minutes window and polls automatically every 10 seconds — no reload needed.
* **Fuller setting descriptions.** Logged-in tracking, Do Not Track, bot tracking, geo cache, language/screen capture, and the weekly digest each gained a plain-English description of their exact effect.
* **Funnels how-to.** The funnels editor now walks through the three steps (name the funnel with ID + display name, list 2+ steps in order as url|/path — trailing * for prefix — or event|Label, then view the funnel card on the Dashboard), matching exactly how funnels are parsed.
* **Diagnostics explained.** One line on how to read the collection endpoint, raw row count, and next maintenance run.
* The admin stylesheet now also loads on the Settings page (checklist card styling). No functional or database changes — documentation/UI only.

= 1.4.0 =
* Added a License section in the plugin's settings where you enter your PBJ license key to unlock automatic updates. The plugin is fully functional without a key; a key covers up to 3 sites, and on pbj.tech itself no key is required.

= 1.3.0 =
* NEW: white-label mode for anonymous / client sites, off by default. Enable with `add_filter( 'pbj_analytics_whitelabel', '__return_true' )` (theme or mu-plugin): the beacon is inlined under a neutral `site-metrics` handle and `SiteMetrics` global instead of an enqueued file, so no plugin-named URL, script id, or config variable appears in the page source; its public REST endpoints use a neutral `metrics/v1` alias; the event opt-in attribute becomes `data-track-event`. Both REST namespaces are always registered, so branded and neutral beacon URLs keep collecting either way; tracking behavior is otherwise identical.

= 1.2.1 =
* Fixed "Avg. time on site" KPI always reading 00:00. `get_engagement_kpis()` only computed engagement from the raw hits table when that table spanned the *entire* selected range; otherwise it fell back to a summary-only path that hard-coded the average time to zero. Since engagement_ms is stored only in the raw table (never in the daily summary), and the default dashboard shows the last 30 days plus a 60-day comparison window, that fallback fired on virtually every install. Engagement, bounce rate, and pages-per-session are now always computed from the raw table over whatever portion of the range it covers; the session headline is still topped up from the summary when retention is shorter than the range.

= 1.2.0 =
* Sessions: 30-minute sliding window per visitor, with per-session sequence on every hit.
* Navigation paths: top 2-step paths (A → B) breakdown.
* Entry pages and exit pages.
* Time on page: end-of-page beacon (pagehide / visibilitychange) updates each pageview row with engagement_ms.
* Scroll depth: 25/50/75/100% milestone events, plus an aggregate depth distribution.
* Referrers: full referrer URL stored alongside the host bucket.
* UTM parameters captured (utm_source/medium/campaign/term/content) with their own dimensions.
* Channel classification: Direct / Organic Search / Paid / Social / Email / Referral, derived server-side from referrer + UTM medium.
* Search engine breakdown (Google / Bing / DuckDuckGo / Yahoo / Yandex / Baidu / Ecosia / Brave / Startpage / Qwant).
* Internal site search: records WordPress `?s=` queries as their own dimension.
* Outbound clicks promoted to a first-class dimension.
* 404 tracking: dedicated dimension for missing-page URLs.
* New vs returning visitors via a longer-rotated salted hash (toggleable; cookieless).
* Region and city (from the ip-api fallback; both toggleable).
* Language (from navigator.language with Accept-Language fallback).
* Screen-size bucket (sm/md/lg/xl).
* Per-author and per-category breakdowns (when posts have authors/categories).
* Funnels: configure ordered steps (url or event), get cumulative session counts + conversion %.
* Goals: list of event labels counted toward a Goal completions KPI.
* Per-page drill-down: click any URL in a top-pages table to see its referrers, channels, countries, devices, avg time, avg scroll.
* Live panel: last-5-minutes pageview count, per-minute bar, latest 15 hits, auto-refreshing.
* Period-vs-period KPI comparison: every headline KPI now shows the delta vs the previous equal-length period.
* CSV export: per-dimension download button on the major tables.
* Weekly email digest: optional HTML summary via wp_mail, with WoW deltas and top tables.
* Public read-only dashboard: optional tokenized URL at /wp-json/pbj-analytics/v1/public/{token}, no login required.
* Per-bot URL list: see exactly what GPTBot / ClaudeBot / Googlebot are fetching, plus their 404s.
* Schema: many new columns on the hits table, new pbj_analytics_funnel_daily table (db version 3, migrated automatically).
* New endpoint: POST /wp-json/pbj-analytics/v1/engagement for end-of-page time/scroll updates.

= 1.1.0 =
* Added separate bot and AI-crawler tracking, recorded server-side (most crawlers don't run JavaScript), split into AI crawlers / search engines / other bots. New "Bots & AI crawlers" dashboard section with category and top-bot breakdowns. Kept entirely separate from human pageview totals.
* Added a "Track bots" setting (on by default).
* Fixed the dashboard charts rendering far too tall: chart canvases are now in fixed-height containers.
* Schema: added the bot_category column (db version 2, migrated automatically).

= 1.0.0 =
* Initial release: pageviews, referrers, cookieless unique visitors, custom events, device/browser/country breakdowns, charted dashboard, configurable retention, self-hosted updater.
