=== No Cookie Analytics – By Arfa ===
Contributors: arfarehman
Tags: analytics, gdpr, tracking, privacy, no cookies
Requires at least: 6.2
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.1.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Privacy-focused analytics with server-side tracking, goals and revenue attribution, and no frontend cookies.

== Description ==

No Cookie Analytics – By Arfa is a privacy-first analytics plugin. It records every visit on your
own server, with **no cookies, no tracking script, and no third-party services**. Because nothing is
measured in the browser, there is nothing to slow your pages down and no analytics cookie banner to
show. Your visitors' raw IP addresses are never stored.

**Reports and dashboards**

* Dashboard with KPI tiles, visitor and page-view trends, a live activity feed, and a countries map
* Acquisition report — marketing channel grouping (direct, organic and paid search, organic and paid
  social, email, affiliate, display, referral) and full UTM campaign performance
* Content report — views broken down by post type, author, category and tag
* Behavior report — entry pages, exit pages, internal site search (including searches that found
  nothing), and a cookieless new-vs-returning visitor split
* Conversions report — goals, conversion rates, and revenue attribution
* Pages, Referrers, Users and 404 reports
* A sortable "Views (30d)" column on the Posts and Pages list tables, and a per-post analytics box
  in the editor

**Goals, conversions and revenue**

* Define goals by exact path, prefix, suffix, substring, regular expression, or "viewed this post",
  with an optional value per conversion
* First-touch and last-touch attribution captured for every session
* WooCommerce revenue attribution by channel, campaign and landing page — only the order id and
  total are stored, never customer details

**Keep years of history without keeping years of personal data**

* Raw page-view records are short-lived by design. Before they are deleted, each day is condensed
  into anonymous per-dimension totals, which are kept for a much longer window (two years by
  default). Long-term trend charts survive a short raw-data retention setting.

**Privacy and compliance built in**

* Honors the Do Not Track and Global Privacy Control browser signals — those visits are never recorded
* A cookieless visitor opt-out, as the `[ncaba_optout]` shortcode or the "Analytics opt-out" block,
  that also erases whatever was already recorded for that visitor
* Registers with the WordPress Privacy Tools (personal-data exporter and eraser) and adds suggested
  privacy-policy text
* Exclude traffic by path, IP address or CIDR range, user agent, post type, or user role

**Delivered to you**

* A designed weekly, monthly or daily email digest with a fully brandable header and footer, plus a
  live preview and one-click test send
* Traffic-anomaly alerts and busy-404 alerts, by email and as an admin notice
* Timeline annotations to mark launches and campaigns on your charts

**For developers**

* Filters and actions throughout the tracking, channel, email and reporting pipeline
* Authenticated REST routes under `ncaba/v1` for stats, reports, time series and annotations
* WP-CLI commands: `wp ncaba stats`, `report`, `rollup`, `purge`, `export`, `send-summary`, `alerts`

== Privacy ==
This plugin stores analytics records in your WordPress database (`wp_ncaba_hits`), including:

* Page URL/path
* Referrer host and the marketing channel it maps to
* Browser/OS/device type
* Anonymized IP hash
* Session key
* Country code
* Whether the request resulted in a 404 (not found)
* Whether the request was an internal site search, and the term used (can be disabled)
* Whether the visitor had been seen before
* UTM campaign parameters (utm_source, utm_medium, utm_campaign), when present in the visited URL
* Timestamp

No raw IP address is stored in the plugin database.

The plugin honors the `DNT` (Do Not Track) and `Sec-GPC` (Global Privacy Control) request headers by
default: those visits are never recorded at all. Visitors can also opt out themselves through the
`[ncaba_optout]` shortcode or the "Analytics opt-out" block, which erases the anonymous records
already stored for them and suppresses future ones — without setting a cookie.

Registered users' records are exposed through the WordPress Privacy Tools, so Tools → Export Personal
Data and Tools → Erase Personal Data both cover this plugin.

Country detection behavior:

1. Uses server-provided geolocation headers when available (for example Cloudflare or GeoIP
   headers).
2. Optional external IP geolocation lookup can be enabled by admin consent in plugin settings.

When external geolocation is enabled, visitor IP is sent to:

* Service: [ipapi.co](https://ipapi.co/) (primary) and [ipwho.is](https://ipwho.is/) (fallback)
* Purpose: country lookup only

Site owners must disclose this in their privacy policy before enabling external lookup.

== External services ==

This plugin can optionally use the third-party services ipapi.co and ipwho.is for country lookup. The lookup
is **disabled by default** and only runs after a site administrator explicitly enables the
"Allow External Geo Lookup" option in plugin settings.

* Services: ipapi.co (https://ipapi.co/) and ipwho.is (https://ipwhois.io/) as fallback
* What is sent: the visitor's IP address (only when the option is enabled and no server-provided
  geo headers are available).
* When: at most once per visitor IP per week on success; failed lookups are retried after one hour.
* Why: to determine the visitor's country code for the analytics dashboard.
* ipapi.co Terms of Service: https://ipapi.co/terms/
* ipapi.co Privacy Policy: https://ipapi.co/privacy/
* ipwho.is Terms: https://ipwhois.io/terms
* ipwho.is Privacy: https://ipwhois.io/privacy

If the option is left disabled, the plugin never contacts ipapi.co or ipwho.is.

No other external service is contacted. All scripts, styles and fonts are bundled locally.

== Features ==

**Privacy and compliance**

* Server-side tracking with no frontend cookies and no tracking script
* Honors Do Not Track and Global Privacy Control signals
* Cookieless visitor opt-out shortcode and block, which also erases past records
* WordPress Privacy Tools exporter and eraser, plus suggested privacy policy text
* Exclude traffic by path, IP address or CIDR range, user agent, post type, and user role

**Reports**

* Dashboard with KPI tiles, visitor and page-view trends, countries, and live activity
* Acquisition report: marketing channel grouping and campaign performance
* Content report: views by post type, author, category and tag
* Behavior report: entry pages, exit pages, internal site search, and new vs returning visitors
* Conversions report: goals, conversion rates, and revenue attribution
* Pages, Referrers, Users and 404 reports
* Sortable "Views (30d)" column on the Posts and Pages list tables
* Per-post analytics meta box in the editor

**Attribution and conversions**

* Goal tracking by exact path, prefix, suffix, substring, regular expression, or post ID
* First-touch and last-touch attribution captured per session
* Channel grouping: direct, organic and paid search, organic and paid social, email, affiliate,
  display, referral
* WooCommerce revenue attribution by channel, campaign and landing page

**Data lifecycle**

* Daily rollups condense each day into anonymous totals before raw records are purged, so you can
  keep years of trends while retaining only a few weeks of raw data
* Separate retention windows for raw hits and aggregated rollups
* Conversion records are stripped of visitor identifiers once the raw window passes

**Reporting and workflow**

* Scheduled daily, weekly or monthly email digest with a fully brandable template
* Traffic anomaly alerts and busy-404 alerts, by email and as an admin notice
* Timeline annotations to mark launches and campaigns on your charts
* CSV export and settings import/export

**Developer surface**

* Filters: `ncaba_should_track`, `ncaba_hit_data`, `ncaba_channel`, `ncaba_retention_days`,
  `ncaba_summary_email_data`, `ncaba_email_html`, `ncaba_email_header_html`,
  `ncaba_email_footer_html`, `ncaba_email_footer_links`, `ncaba_email_headers`,
  `ncaba_banner_campaigns`, `ncaba_banner_eligible_screen`, `ncaba_search_engine_hosts`,
  `ncaba_social_hosts`, `ncaba_bot_user_agent_pattern`
* Actions: `ncaba_hit_recorded`, `ncaba_goal_converted`, `ncaba_visitor_opted_out`,
  `ncaba_alerts_raised`, `ncaba_email_sent`, `ncaba_cleanup_complete`
* Authenticated REST routes under `ncaba/v1`: `stats`, `report/<name>`, `timeseries`, `annotations`
* WP-CLI: `wp ncaba stats`, `report`, `rollup`, `purge`, `export`, `send-summary`, `alerts`

== Installation ==
1. Upload the `no-cookie-analytics-by-arfa` folder to `/wp-content/plugins/` (or install through the
   WordPress plugin installer).
2. Activate the plugin through the **Plugins** screen.
3. Open the **Analytics** menu in the admin area.

== Frequently Asked Questions ==

= Does this plugin set cookies? =

No. Tracking is performed on the server when pages are requested. The visitor opt-out control uses
`localStorage` only to remember which button label to show; the opt-out itself is stored server-side
against an irreversible hash.

= Where is data stored? =

In custom tables in your WordPress database: `wp_ncaba_hits` (raw page views), `wp_ncaba_sessions`
(session summaries), `wp_ncaba_daily` (anonymous daily rollups), `wp_ncaba_conversions` (goals and
revenue), `wp_ncaba_annotations`, and `wp_ncaba_optout`.

= How can I keep long-term trends without keeping long-term visitor data? =

That is exactly what the daily rollups do. Set a short raw retention window (for example 30 days) and
a long rollup retention window (the default is two years). Before the purge runs, each day is
condensed into per-dimension totals that contain no visitor identifiers at all.

= How are new and returning visitors detected without cookies? =

By checking whether the anonymized visitor hash has been seen in an earlier session. Because the hash
is derived from the IP address, this is an approximation — visitors on a new network read as new.

= Does it work with WooCommerce? =

Yes. When enabled, each order is recorded as a conversion with its total, attributed to the channel,
campaign and landing page that brought the customer in. Only the order ID and total are stored; no
customer details are copied.

= Can I track goals without WooCommerce? =

Yes. Define a goal on any path — a thank-you page, a confirmation screen, a specific post — and
optionally give it a value so the reports can estimate the revenue each channel produces.

== Screenshots ==
1. Analytics dashboard with KPI tiles and visitor trends.
2. Acquisition report showing marketing channel grouping.
3. Conversions report with goals and revenue attribution.
4. Settings screen with privacy, exclusion and email branding options.
5. The branded email digest as recipients receive it.

== Changelog ==

= 1.1.0 =
Major feature release. Compatible with WordPress 7.1.

**Privacy and compliance**
* Honor the `DNT` and `Sec-GPC` request headers; those visits are never recorded.
* Added a cookieless visitor opt-out as both the `[ncaba_optout]` shortcode and an
  "Analytics opt-out" block. Opting out erases records already stored for that visitor and
  suppresses future ones through a server-side list, so no cookie is needed.
* Registered a WordPress Privacy Tools exporter and eraser, and added suggested privacy policy text
  to Settings → Privacy.
* Added tracking exclusions for paths (with wildcards), IP addresses and CIDR ranges, user agent
  substrings, and post types, alongside the existing role exclusions.

**Deeper server-side metrics**
* Internal site search report, including which searches returned no results.
* Content report: views broken down by post type, author, category and tag.
* New vs returning visitor split, derived without cookies.
* Entry and exit page reports, backed by a new session summary table.
* Sortable "Views (30d)" column on the Posts, Pages and custom post type list tables.

**Attribution and conversions**
* Goal tracking with exact, prefix, suffix, substring, regular expression and post ID matching, an
  optional value per conversion, and once-per-session deduplication.
* First-touch and last-touch attribution captured per session.
* Channel grouping into direct, organic/paid search, organic/paid social, email, affiliate, display
  and referral, with an `ncaba_channel` filter for custom rules.
* WooCommerce revenue attribution by channel, campaign and landing page.

**Data lifecycle**
* Daily rollups condense every day into anonymous per-dimension totals before the retention purge
  runs, so long-term trends survive a short raw-data window. Separate rollup retention setting,
  defaulting to two years.
* Conversion rows keep their business value but have visitor identifiers stripped once the raw
  retention window passes.

**Reporting and workflow**
* Scheduled daily, weekly or monthly email digest with a responsive, Outlook-safe template whose
  header and footer are fully configurable, including logo, accent color, tagline, intro note,
  company details, postal address and legal line, all supporting merge tags.
* Live email preview and one-click test send from the settings screen.
* Traffic anomaly alerts comparing yesterday against a trailing 7-day baseline, and alerts for 404
  paths crossing a hit threshold. Both surface by email and as an admin notice.
* Timeline annotations to mark launches and campaigns against your charts.

**Developer surface**
* New filters and actions throughout the tracking, channel, email and banner pipelines.
* Authenticated REST routes under `ncaba/v1` for stats, reports, time series and annotations, plus
  two public routes a visitor uses to exercise their own opt-out.
* WP-CLI commands: `wp ncaba stats`, `report`, `rollup`, `purge`, `export`, `send-summary`, `alerts`.

**Admin experience**
* New branded announcement banner on the plugin screens, the WordPress Dashboard and the Plugins
  page, carrying a persistent "Leave a review" call to action. Its close button hides it for the
  current view; it returns on the next load. The `ncaba_banner_eligible_screen` and
  `ncaba_banner_campaigns` filters tune or disable it.
* Reorganized menu: new Acquisition, Content, Behavior, Conversions and Annotations screens. The
  Campaigns report moved under Acquisition; its old URL still resolves.

**Compatibility**
* Verified against WordPress 7.1 core APIs and bumped the tested-up-to header.
* Passes the official WordPress.org `plugin-review` and `plugin-check` PHPCS rulesets, and Plugin
  Check's direct-database and escaping sniffs, with no errors or warnings.
* All identifier interpolation in reporting SQL now runs through `esc_sql()`; the daily-rollup
  upsert is built only from literal placeholder groups; uninstall uses `delete_metadata()` instead
  of a direct usermeta query.

= 1.0.17 =
* Compatibility with WordPress 7.1: verified against current core APIs and bumped the "Tested up to" header.
* Passed all field-separator, enclosure, and escape arguments explicitly to `fputcsv()` in the CSV export so it
  no longer relies on the default `$escape` value, which is deprecated in PHP 8.4+.
* Declared `Requires PHP: 7.4` in the plugin header and readme to match the code's actual language level.

= 1.0.16 =
* Added UTM campaign tracking: `utm_source`, `utm_medium`, and `utm_campaign` query parameters are now captured
  per hit, with a new Campaigns Report (Analytics → Campaigns Report) showing visits and visitors grouped by
  source, medium, and campaign for the last 30 days.

= 1.0.15 =
* Added a per-post Analytics meta box in the editor sidebar (Posts, Pages, and other public post types), showing
  total views, unique visitors, a 30-day change badge, a 14-day views sparkline, and the post's top referrers.
* Added an index on `post_id` to the hits table to keep per-post queries fast.

= 1.0.14 =
* Redesigned the dashboard to match a new reference layout: welcome subtitle, grouped date-range control
  with a clear button, redesigned KPI tiles with period-over-period percentage change badges, icon badges
  on the footer info cards, and an empty-state illustration for "Top Active Pages" when nothing is live.
  New accent color throughout (medium blue) replacing the previous neon-cyan accent.
* Added real period-over-period comparison: each KPI tile now shows a percent change vs. the immediately
  preceding period of equal length (e.g. this week vs. last week).

= 1.0.13 =
* Added a "Page Views Overview" chart to the dashboard, matching the style of Visitors Overview, showing
  total tracked page views over the selected range (as opposed to unique visitors).

= 1.0.12 =
* Added a 404 Report (Analytics → 404 Report) listing missing pages visitors hit, with hit counts and
  last-seen times, to help find broken links to fix or redirect.
* Added an `is_404` column to the hits table to support the new report.
* Moved front-end tracking from the `init` hook to `template_redirect` so conditional tags like `is_404()`
  (and `get_queried_object_id()`) are reliable at tracking time — the main query hasn't run yet at `init`.

= 1.0.11 =
* Reverted page/section headings (Dashboard, Settings, report pages) from the gradient brand color back to
  plain black text, matching the pre-1.0.9 look.

= 1.0.10 =
* Reverted buttons and card/section border colors to the original neutral style after feedback that the
  gradient buttons and blue-tinted borders introduced in 1.0.9 didn't look good; kept the animated,
  brand-colored charts.

= 1.0.9 =
* Redesigned admin UI with a neon-blue brand accent (matches the site theme's primary color), plain CSS only —
  no external CSS framework, so there is no risk of conflicting with other plugins' styles.
* Dashboard grid now uses responsive layout classes instead of inline styles, so cards stack properly on
  narrow screens instead of being squeezed.
* Charts (visitors trend, country donut) now animate on load/refresh, use the brand color palette, and show
  a styled tooltip; the trend chart has a soft gradient fill under the line.
* KPI stat tiles and the realtime counter now animate ("count up") when values change instead of jumping
  instantly.
* Fixed the bounce-rate "quality" tag not updating color after a live dashboard refresh.
* Fixed a color-palette mismatch between the initial server-rendered country legend and the JS-rendered
  legend after a refresh.
* Fixed the WordPress Dashboard "Quick View" widget never loading its stylesheet (it only loaded on the
  plugin's own admin screens), so the widget now renders styled instead of as plain unstyled text.
* Report tables now scroll horizontally on small screens instead of overflowing the page.
* Settings screen now uses the same card layout and typography as the rest of the plugin (it was previously
  missing the shared styling wrapper).
* Added a subtle live-activity pulse indicator to the Realtime card and dashboard widget.

= 1.0.8 =
* Dashboard: redesigned info tooltips to use Dashicons with cleaner markup and tooltip text via CSS `::after`.
* Dashboard: Visitors Overview chart now shows hourly data when the "Last 24 hours" filter is selected.
* Fixed hourly chart data accuracy by bucketing visits in the WordPress site timezone.
* Improved country detection with more server geo headers, better proxy IP resolution, and optional
  external lookup via ipapi.co with ipwho.is fallback (removed browser-language country guessing).
* Fixed recent activity timestamps by storing hits in site time and formatting relative times correctly.
* Settings: added role-based tracking exclusion with a custom searchable multiselect when "Skip tracking
  for logged-in users" is enabled.
* Admin notices (including warnings) now render before the analytics layout wrapper to avoid layout issues.
* Tracking now records page paths with query strings (for example `/blog?123456`) as separate entries in reports.

= 1.0.7 =
* Removed UTF-8 byte order marks (BOM) from PHP sources so activation no longer sends accidental
  output to the browser.
* Uninstall: reliable table drop, clear all related and legacy cron hooks, and remove cached
  geo lookup transients.
* Deactivation: clear legacy cleanup cron hook names in addition to the canonical event.

= 1.0.6 =
* Renamed plugin to "No Cookie Analytics – By Arfa"; text domain and translation template are
  `no-cookie-analytics-by-arfa` (Domain Path: `/languages`).
* Main bootstrap file is `no-cookie-analytics-by-arfa.php`; directory slug `no-cookie-analytics-by-arfa`.
* PHP class and constant prefix `NCABA_*` (e.g. `NCABA_VERSION`, `NCABA_Activator`); runtime
  identifiers use lowercase `ncaba_*` / `ncaba-` (database table `{prefix}ncaba_hits`, options,
  hooks, AJAX, and asset handles). Legacy `cfaba_*`, `cfba_*`, and mistaken `NCABA_*` option keys
  or table names migrate automatically on upgrade.
* Plugin URI points to a reliable HTTPS profile page; localized admin strings and dashboard JS
  escaping improvements.
* Bumped tested-up-to header for current WordPress.

= 1.0.5 =
* Previous branding and slug iteration; see older releases for detail.

= 1.0.4 =
* Raised minimum WordPress version to 6.2 for safe `%i` identifier placeholders in
  `$wpdb->prepare()`.
* Hardened admin and cron SQL (prepared statements, `esc_like()` for `LIKE` patterns).
* Replaced `parse_url()` with `wp_parse_url()`; removed redundant `fclose()` on export stream.
* Settings import notices use per-user transients; validated upload temp files with
  `is_uploaded_file()`.
* Added readme short description; direct-access guard on settings view template.

= 1.0.3 =
* Bundled Chart.js and Poppins assets locally (removed CDN dependency).
* Added explicit admin consent toggle for external geolocation lookup.
* Updated privacy disclosure and reviewer-oriented readme details.

= 1.0.2 =
* Improved admin UI and tooltip behavior.

= 1.0.1 =
* Added richer visitor identity and dashboard/report improvements.

= 1.0.0 =
* Initial release.

== Upgrade Notice ==

= 1.1.0 =
Adds goals and conversions, channel grouping, WooCommerce revenue attribution, long-term daily
rollups, branded email digests, alerts, a REST API and WP-CLI commands. New database tables are
created automatically on upgrade; existing data is preserved.
