=== MilkStats ===
Contributors:      javdgraaf
Tags:              analytics, privacy, gdpr, statistics, cookieless
Requires at least: 5.8
Tested up to:      7.1
Requires PHP:      7.4
Stable tag:        1.8.0
License:           GPL-2.0-or-later
License URI:       https://www.gnu.org/licenses/gpl-2.0.html

Privacy-friendly, cookieless visitor statistics — no cookie banner needed, no external services.

== Description ==

**MilkStats** keeps visitor statistics without collecting personal data.
All data stays local in your own WordPress database — nothing is shared with
external analytics services (no Google Analytics, no external scripts or
fonts).
A product by [5Names](https://5names.nl).

= What is measured? =

* **Page views** — counted and aggregated per page, per day
* **Sessions** — how many unique visitor sessions there were
* **Time on page** — how long someone stayed on a page
* **Navigation paths** — which page most often leads to which next page
* **Sources** — did the visitor arrive via a search engine, social media, a
  referring site, an AI assistant, or directly? Plus UTM campaign tags
  (`utm_source`, `utm_medium`, `utm_campaign`) if you use them in your own
  marketing links.
* **Events** — clicks on outbound links and download links are detected
  automatically, plus optional custom events via the `data-milkstats-event`
  attribute. See "Custom events" below.
* **AI crawler visibility** — how often known AI crawlers (GPTBot, ClaudeBot,
  PerplexityBot, and others) visit your site, separate from human traffic.

= What is NEVER stored? =

* No IP addresses
* No tracking cookies — the session ID lives only in the browser's
  `sessionStorage` and disappears as soon as the tab is closed. The only
  cookie this plugin can ever set is the optional opt-out cookie described
  below, and only if you or a visitor chooses to set it.
* No browser fingerprinting
* No full referrer URLs — only the domain (e.g. "google.com"), never the
  path or a search query that might be contained in it
* No data sent to external parties

= How does it work technically? =

On every page view, a small, first-party JavaScript file (`assets/tracker.js`)
sends an AJAX request to your own `admin-ajax.php`. That request contains the
page URL, page title, a random session ID, and — only on the first page view
of a session — the hostname of the referring site and any UTM parameters.
When the page is left, the time on page is sent afterwards via
`navigator.sendBeacon`.

This data ends up in the following tables in your WordPress database:

1. `wp_milkstats_pageviews` — daily totals per page. Kept indefinitely: just
   counts, no session information.
2. `wp_milkstats_session_events` — individual page views per session, with
   time on page. Automatically deleted after the configured retention
   period.
3. `wp_milkstats_sessions` — one row per session with the traffic source
   (first-touch attribution). Also cleaned up after the retention period.
4. `wp_milkstats_events` — custom events (outbound link clicks, downloads,
   manual events). Cleaned up after the retention period, same as session
   data.
5. `wp_milkstats_device_stats` — daily aggregated device/browser/OS counts.
   Kept indefinitely, like page totals — never traceable to an individual.
6. `wp_milkstats_ai_crawler_hits` — daily aggregated hits from known AI
   crawlers. Kept indefinitely, like page totals.

A daily WP-Cron job cleans up session data older than the configured
retention period. Page totals are never deleted. Bots are recognized and
ignored based on the User-Agent.

= Custom events =

Besides page views, MilkStats also measures events, without any
configuration needed:

* **Outbound links** — a click on a link to another domain is automatically
  recorded, with the domain as the label.
* **Downloads** — a click on a link to a file with a known download
  extension (pdf, zip, docx, xlsx, and more) is automatically recorded, with
  the file name as the label.
* **Manual events** — add the `data-milkstats-event="label"` attribute to a
  link, button or `<form>` to track that click or submission as a custom
  event, for example:
  `<a href="#" data-milkstats-event="Quote requested">Request a quote</a>`
  or `<form data-milkstats-event="Contact form submitted">…</form>`.

Events count if the visitor is not excluded (see Settings) and are shown on
the statistics page under "Events", with the top labels per type.

= Excluding yourself (opt-out) =

Besides the role exclusion (only works while logged in), you can also
exclude yourself — or an external tester — without logging in:

* **Via the admin bar** — administrators see a MilkStats item at the top
  ("tracking on"/"tracking off") to flip this with one click.
* **Via a link** — visit `?milkstats_optout=1` to exclude yourself, or
  `?milkstats_optout=0` to be counted again. Also works while logged out,
  handy to share with external testers.
* **Via the settings page** — a button ("Exclude my visits in this browser")
  showing the current status.

This sets a first-party cookie (`milkstats_optout`) in that one browser. The
cookie itself has no tracking purpose — purely a toggle — and works alongside
the role exclusion, not instead of it.

= Settings =

Under **Site Analytics → Settings** you can configure:

* **Excluded roles** — which user roles are never counted (default:
  administrator, editor, author, contributor)
* **Exclude yourself** — a button to exclude your own visits in the current
  browser, even while logged out (see "Excluding yourself" above)
* **Member segment** — optional: which role(s) should be counted separately
  as a "logged-in segment" (e.g. members, clients, subscribers), with a
  custom name for that segment in the statistics. Up to three additional
  named segments can be configured, each pickable from a dropdown on the
  statistics page.
* **Retention period** — after how many days session data (time on page,
  navigation paths, sources) is automatically deleted

= Where do I see the statistics? =

* A compact overview on the WordPress dashboard (widget)
* A full statistics page under **Site Analytics** in the main menu, with a
  rolling period filter (7/30/90/365 days) plus a calendar period picker
  (today/yesterday, this/last week, this/last month, this/last quarter,
  this/last year), bar chart, top pages, navigation paths, source breakdown,
  device/browser/OS breakdown, and AI crawler visibility

= Credits =

The admin screens use the [Inter](https://rsms.me/inter/) typeface by Rasmus
Andersson, bundled with the plugin under the SIL Open Font License 1.1
(`assets/fonts/OFL.txt`). It is served from your own site — never from an
external font CDN.

== Installation ==

1. Upload the `milkstats` folder to `/wp-content/plugins/`.
2. Activate the plugin via **Plugins** in WordPress.
3. Go to **Site Analytics → Settings** to set roles, segment and retention
   period as needed — the default settings also work fine without changes.
4. View your statistics under **Site Analytics** in the main menu.

== Frequently Asked Questions ==

= Is this plugin GDPR-compliant without a cookie banner? =

Yes. No tracking cookies are placed, no IP addresses are stored, and no data
is shared with third parties. The session ID is generated in the browser
itself, lives only in `sessionStorage` (not persistent), and cannot be traced
back to an individual. The only cookie the plugin ever sets is the optional
opt-out cookie, and only if you or a visitor chooses to set it — that cookie
serves no tracking purpose.

= Are administrators/editors counted? =

Not by default — administrator, editor, author and contributor are excluded.
This can be changed under Settings.

= Can I exclude myself, even while logged out? =

Yes. Besides the role exclusion (logged in only), you can exclude yourself
via the admin bar, the settings page, or the `?milkstats_optout=1` link in
the browser you're currently using — handy for testing while logged out or
to share with an external tester. See "Excluding yourself (opt-out)" above.

= Does this work with caching plugins? =

For regular visitor statistics, yes: that tracking runs via a separate AJAX
request after the page loads, so a cached page is still counted correctly.
The AI crawler report is an exception: that runs server-side (WordPress must
actually run to see a visit), so visits from AI crawlers to fully cached
pages (e.g. a "supercached" page with WP Super Cache) are missed in that
report.

= What happens to my data if I deactivate or delete MilkStats? =

Deactivating the plugin (from the Plugins screen) leaves all data untouched
— your tables and settings are still there if you reactivate later.
Deleting the plugin (via "Delete" on the Plugins screen, which runs its
`uninstall.php`) permanently removes every MilkStats database table (page
views, sessions, session events, device stats, custom events, AI crawler
hits) and every MilkStats setting. This cannot be undone, so export any data
you want to keep (see the Export dashboard (.html)/CSV buttons on the
statistics page) before deleting the plugin.

= Can I use this on multiple sites? =

Yes, the plugin is deliberately kept generic: every site-specific choice
(roles, segment, retention period) is configurable, not hardcoded.

== Screenshots ==

1. The compact "Visitor Statistics" dashboard widget — today, the last 7
   days and the last 30 days at a glance, with a 14-day trend line and the
   top visited pages, right on the WordPress dashboard.
2. The Site Analytics page: rolling and calendar period filters, the privacy
   badges, the stat cards with period-over-period comparison, the "Views per
   day" chart and the "Visitor sources" breakdown (search engines, referring
   sites, social media, AI assistants and direct visits).
3. Device, browser and operating-system breakdown — classified server-side,
   the raw User-Agent is never stored — next to the most visited pages with
   average time on page.
4. The most common navigation paths: which page most often leads to which
   next page.
5. The AI-crawler visibility report: how often GPTBot, ClaudeBot,
   PerplexityBot, Google-Extended and other AI crawlers hit the site,
   separate from human traffic, with a per-crawler and per-page breakdown.
6. The Settings page: excluded roles, the logged-in member segment with a
   custom label, self-exclusion, and the session-data retention period.

== Changelog ==

= 1.8.0 =
* Existing installs of the older "Pion Analytics" plugin (and its interim
  "AVG Proof Site Analytics" release) are now upgraded to MilkStats
  automatically on activation, without losing any historical data. The
  existing page-view and session tables are renamed into place (never
  copied, so nothing is duplicated or left orphaned), the old Dutch
  visitor/member labels are converted to the format MilkStats uses, and the
  previous plugin's scheduled cleanup task is removed. To switch over:
  deactivate the old plugin, install MilkStats, and activate it.
* The admin menu item is now labelled "MilkStats" (was "Site Analytics") and
  uses the MilkStats icon instead of a generic chart-bar icon.
* Every dashboard tile now has a small ⓘ icon in its top-right corner —
  click it for a short explanation of exactly what that tile shows. The same
  icons and explanations are included in the "Export dashboard (.html)"
  file, for the tiles that appear there.
* New "Help" menu item, right after "Settings": a full explanation of the
  dashboard plus a dedicated section on how MilkStats protects visitor
  privacy (what is and isn't stored, retention periods, excluded roles, and
  the opt-out cookie).

= 1.7.0 =
* Excel export has been removed entirely (the "Export Excel" button and the
  vendored PhpSpreadsheet library are both gone). A formula-driven Excel
  workbook turned out to be the wrong format for a shareable, interactive
  dashboard export — the new .html export below replaces it.
* New "Export dashboard (.html)" button next to Export CSV: generates a
  single, self-contained .html file with the full Site Analytics dashboard
  (KPIs, the views-per-day chart, visitor sources, device/browser/OS
  breakdowns, top pages, and the AI crawler report) for all 14 period
  options at once. It needs no WordPress access or internet connection to
  view — just open the file in any browser — and switching between periods
  recalculates everything instantly with plain JavaScript, no page reload
  and no spreadsheet formulas involved.

= 1.6.0 =
* New calendar period picker on the statistics page, next to the existing
  rolling filter (7/30/90/365 days): today/yesterday, this/last week,
  this/last month, this/last quarter, and this/last year. Unlike the rolling
  filter, these are calendar-aligned (e.g. "last month" is always the full
  previous calendar month, not the last 30 days).
* Period-over-period comparison now also works for calendar periods. For a
  "this ..." period still in progress (e.g. this month, part-way through),
  the comparison is capped to the same number of elapsed days in the
  previous period, so the percentage stays a fair, apples-to-apples
  comparison rather than always favoring the completed period.
* CSV export now reflects whichever period control is active (rolling or
  calendar), including the file name.

= 1.5.0 =
* New AI-crawler visibility report: see how often known AI crawlers (GPTBot,
  ClaudeBot, PerplexityBot, Google-Extended, CCBot, and others) visit your
  site, separate from human traffic — with a top-pages breakdown per crawler.
  Detected server-side, since crawlers don't run the JavaScript tracker.
* Known limitation: full-page caching can hide crawler visits from this
  report (documented on the statistics page and in the FAQ above).
* New "Export CSV" button on the statistics page: a lightweight export of
  the top pages table.
* The statistics page can now switch between multiple configured segments
  via a dropdown next to the period selector, without a trip to Settings.
  Up to three additional named segments can be configured under Settings,
  alongside the existing one.

= 1.4.0 =
* Self opt-out: exclude your own visits via an admin bar toggle, a settings
  page button, or a manual `?milkstats_optout=1` URL parameter — works even
  while logged out, alongside the existing role exclusion.
* Privacy policy text and the WP Privacy Policy Guide integration updated to
  mention the new opt-out cookie (functional only, no tracking purpose).

= 1.3.0 =
* Custom event tracking: outbound links and file downloads are detected
  automatically, plus a manual `data-milkstats-event` attribute for custom
  events (e.g. form submissions).
* New "Events" card on the statistics page with top event labels per type.
* Privacy policy text and the WP Privacy Policy Guide integration updated to
  mention the new events data.

= 1.2.0 =
* Renamed from AVG Proof Site Analytics to MilkStats.
* Full i18n: English source strings with a bundled Dutch translation.
* Period-over-period comparison on the page-views and sessions stat cards.
* Landing & exit pages report.
* AI assistants (ChatGPT, Perplexity, Gemini, Copilot, Claude.ai, etc.) as a
  separate traffic-source category.
* Device, browser and OS breakdown, classified server-side — the raw
  User-Agent string is never stored.
* Privacy policy integration via wp_add_privacy_policy_content().
* Visual redesign of the statistics page: a real line chart (this period vs.
  previous period), donut charts for traffic sources and device/browser/OS,
  and a refreshed MilkStats brand look.

= 1.1.0 =
* Added source tracking: referrer category (search engine, social, referral,
  direct) and UTM campaign tags, with first-touch attribution per session.
* Version-based upgrade routine so existing installs automatically get the
  new table without reinstalling.

= 1.0.0 =
* First release: page views, sessions, time on page, navigation paths,
  configurable role filtering and member segment, dashboard widget and
  statistics page with period filter.
