{"id":46327785,"url":"https://github.com/fabiodalez-dev/faz-cookie-manager","last_synced_at":"2026-04-26T11:01:12.424Z","repository":{"id":341547137,"uuid":"1170472151","full_name":"fabiodalez-dev/FAZ-Cookie-Manager","owner":"fabiodalez-dev","description":"Free, open-source WordPress cookie consent plugin (GPL-3.0). Cloud-free fork with browser-based cookie scanner, GDPR/ePrivacy compliance, GCM v2, IAB TCF v2.3.","archived":false,"fork":false,"pushed_at":"2026-04-24T14:39:46.000Z","size":9506,"stargazers_count":90,"open_issues_count":1,"forks_count":13,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-04-24T16:41:16.924Z","etag":null,"topics":["ccpa","cookie-banner","cookie-compliance","cookie-consent","eprivacy","gdpr","google-consent-mode","gpl-3","gpl3","iab-tcf","open-source","php","privacy","self-hosted","wordpress","wordpress-plugin"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fabiodalez-dev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-02T06:47:47.000Z","updated_at":"2026-04-24T14:39:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/fabiodalez-dev/FAZ-Cookie-Manager","commit_stats":null,"previous_names":["fabiodalez-dev/faz-cookie-manager"],"tags_count":32,"template":false,"template_full_name":null,"purl":"pkg:github/fabiodalez-dev/FAZ-Cookie-Manager","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabiodalez-dev%2FFAZ-Cookie-Manager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabiodalez-dev%2FFAZ-Cookie-Manager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabiodalez-dev%2FFAZ-Cookie-Manager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabiodalez-dev%2FFAZ-Cookie-Manager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fabiodalez-dev","download_url":"https://codeload.github.com/fabiodalez-dev/FAZ-Cookie-Manager/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabiodalez-dev%2FFAZ-Cookie-Manager/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32294591,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T09:34:17.070Z","status":"ssl_error","status_checked_at":"2026-04-26T09:34:00.993Z","response_time":129,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ccpa","cookie-banner","cookie-compliance","cookie-consent","eprivacy","gdpr","google-consent-mode","gpl-3","gpl3","iab-tcf","open-source","php","privacy","self-hosted","wordpress","wordpress-plugin"],"created_at":"2026-03-04T17:00:17.371Z","updated_at":"2026-04-26T11:01:12.414Z","avatar_url":"https://github.com/fabiodalez-dev.png","language":"PHP","readme":"# FAZ Cookie Manager\r\n\r\n**The only cookie consent plugin you need. 100% free, no required cloud account, no subscriptions.**\r\n\r\n---\r\n\r\n**Tired of cookie consent plugins that lock essential features behind paywalls, require cloud accounts, or send your visitors' data to third-party servers?**\r\n\r\nFAZ Cookie Manager is a WordPress plugin that helps you implement cookie consent and privacy workflows for international regulations -- completely free, with no strings attached.\r\n\r\nNo account to create. No required cloud service to connect. No \"premium\" plan to unlock basic features like consent logging or geo-targeting. Core consent features run on your own server, and you own all your data.\r\n\r\n## Why FAZ Cookie Manager?\r\n\r\nMost cookie consent plugins follow the same pattern: a free version with crippled features, and a paid tier starting at $10-50/month that unlocks what you actually need. FAZ Cookie Manager breaks that model:\r\n\r\n| Feature | Others (free) | Others (paid) | FAZ Cookie Manager |\r\n|---|---|---|---|\r\n| Cookie banner | Limited | Full | **Full** |\r\n| Cookie scanner | No | Yes | **Yes** |\r\n| Consent logging + CSV export | No | Yes | **Yes** |\r\n| Google Consent Mode v2 | No | Yes | **Yes** |\r\n| IAB TCF v2.3 + GVL | No | Yes | **Yes** |\r\n| Geo-targeting | No | Yes | **Yes** |\r\n| Multi-language (180+) | No | Yes | **Yes** |\r\n| Cloud dependency | No | **Yes** | **No** |\r\n| Price | Free | $10-50/mo | **Free forever** |\r\n\r\n\u003e **A note on IAB TCF v2.3:** The plugin includes a fully functional IAB TCF v2.3 CMP implementation -- TC String encoding, GVL integration, vendor consent UI, and all required `__tcfapi()` commands work correctly. However, for the TC String to be recognized by the ad-tech supply chain, the CMP must be registered with IAB Europe (which requires an annual fee). CMP registration is on the roadmap. If you'd like to help make it happen, consider supporting the project:\r\n\u003e\r\n\u003e [![Buy Me A Coffee](https://img.shields.io/badge/Buy%20Me%20A%20Coffee-support-yellow?style=flat\u0026logo=buy-me-a-coffee)](https://buymeacoffee.com/fabiodalez)\r\n\r\n---\r\n\r\n## Screenshots\r\n\r\n### Cookie Consent Banner\r\nConsent banner with Customize, Reject All, and Accept All buttons. Appears on first visit, fully responsive and keyboard accessible.\r\n\r\n![Cookie consent banner](assets/screenshot-1.png)\r\n\r\n### Dashboard\r\nAnalytics overview with pageviews chart, consent distribution (accept/reject rates), and quick links to all plugin sections.\r\n\r\n![Dashboard](assets/screenshot-2.png)\r\n\r\n### Cookie Banner Editor\r\nCustomize layout (box, bar, popup), position, theme (light/dark), and regulation type (GDPR/CCPA/both) with a live preview. Includes tabs for Content, Colours, Buttons, Preference Center, and Advanced settings.\r\n\r\n![Cookie Banner editor](assets/screenshot-3.png)\r\n\r\n### Cookies Management\r\nView all detected cookies organized by category (Necessary, Functional, Analytics, Performance, Advertisement). Edit, delete, or add cookies manually. Integrated with the Open Cookie Database (2,242 definitions) for automatic categorization.\r\n\r\n![Cookies management](assets/screenshot-4.png)\r\n\r\n### Cookie Scanner\r\nBuilt-in browser-based scanner with multiple scan depths: Quick (10 pages), Standard (100), Deep (1,000), or Full scan. Runs locally -- no external service, no API limits.\r\n\r\n![Cookie scanner](assets/screenshot-5.png)\r\n\r\n### Consent Logs\r\nComplete audit trail of every visitor's consent decision. Shows consent ID, status, categories chosen, anonymized IP, and page URL. Search, filter, and export to CSV for GDPR accountability.\r\n\r\n![Consent Logs](assets/screenshot-6.png)\r\n\r\n### Google Consent Mode v2\r\nConfigure all 7 consent signal types with default and granted states. Includes Google Additional Consent Mode (GACM) for ad technology provider IDs.\r\n\r\n![Google Consent Mode](assets/screenshot-7.png)\r\n\r\n### Languages\r\nSelect from 180+ available languages. The banner text adapts automatically to the visitor's browser language.\r\n\r\n![Languages](assets/screenshot-8.png)\r\n\r\n### Settings\r\nGlobal controls: enable/disable banner, exclude pages, consent log retention, scanner limits, Microsoft UET/Clarity consent APIs, and IAB TCF v2.3 toggle with CMP ID and Purpose One Treatment options.\r\n\r\n![Settings](assets/screenshot-9.png)\r\n\r\n---\r\n\r\n## Compliance\r\n\r\n| Standard | Status | Details |\r\n|----------|--------|---------|\r\n| GDPR (EU) | Assists | Opt-in model, granular consent, right to withdraw |\r\n| ePrivacy Directive | Assists | Consent-based script blocking support |\r\n| CCPA / CPRA (California) | Supported | \"Do Not Sell\" opt-out, GPC signal detection |\r\n| Garante Privacy LG 2021 (Italy) | Assists | Equal-weight buttons, no scroll-as-consent, 6-month max expiry option |\r\n| EDPB Guidelines | Assists | Scroll != consent, no pre-checked categories, equal button prominence |\r\n| IAB TCF v2.3 | Supports | Full `__tcfapi()` CMP, GVL integration, vendor consent UI, DisclosedVendors segment |\r\n| Google Consent Mode v2 | Supports | Default-denied signals, consent update on interaction |\r\n| LGPD (Brazil) | Supported | Consent-based model |\r\n| POPIA (South Africa) | Supported | Opt-in consent |\r\n| WCAG 2.1 AA | Accessibility-focused | Keyboard navigation, focus indicators, ARIA labels |\r\n| WP Consent API | Supports | Registered via `wp_consent_api_registered_` filter |\r\n\r\n\u003e **Legal Disclaimer:** Compliance status depends on correct plugin configuration for your specific use case and does not constitute a legal guarantee. This table is for informational purposes only and is not legal advice. Consult a qualified legal professional for your jurisdiction.\r\n\r\n### Automated Compliance Tests\r\n\r\nPlaywright tests verify consent behavior and policy-oriented safeguards at runtime:\r\n\r\n- TF01-TF18: Full functional test suite covering banner display, cookie blocking, consent flow, mobile, accessibility, revocation, logging, GCM signals, and cookie declarations\r\n- P05: No ambiguous button labels (dark pattern check)\r\n- G07: Non-technical toggles OFF by default\r\n- I08: Technical cookies non-disableable\r\n- T01-T03: IAB TCF `__tcfapi` CMP stub, TC String format, cross-frame messaging\r\n- GCM01-GCM05: Google Consent Mode default-denied, granted on accept, revocation\r\n- CD01-CD03: Cookie declarations, descriptions, categories\r\n- VIS01-VIS09: Visual integrity checks across banner types and preference centers\r\n- IAB01-IAB39: IAB Settings page, GVL admin page, vendor selection, TC String validation\r\n\r\n**The test suite includes automated consent, privacy, accessibility, and integration checks across frontend, admin, scanner, GCM/TCF, visual integrity, and IAB flows.**\r\n\r\n---\r\n\r\n## Installation\r\n\r\n1. Download the latest release from [GitHub Releases](https://github.com/fabiodalez-dev/FAZ-Cookie-Manager/releases)\r\n2. Upload the `faz-cookie-manager` folder to `/wp-content/plugins/`\r\n3. Activate in WordPress admin \u003e Plugins\r\n4. Go to **FAZ Cookie** in the admin sidebar\r\n5. Click **Scan Site** on the Cookies page to detect cookies\r\n6. Customize banner design, text, and regulation type\r\n\r\n### Requirements\r\n\r\n- WordPress 5.0+\r\n- PHP 7.4+\r\n- MySQL/MariaDB\r\n- Built-in Open Cookie Database snapshot included; `Update Definitions` refreshes it from GitHub.\r\n- Core consent features run locally. Optional refresh/download features may contact GitHub, IAB Europe, MaxMind, or the AMP CDN depending on which features you enable and use.\r\n\r\n---\r\n\r\n## Features (detailed)\r\n\r\n### Cookie Banner\r\n\r\n- **Three banner types**: Classic (bar), Popup (modal), Box (widget)\r\n- **Configurable position**: Top, bottom, or any corner\r\n- **Three legislation modes**: GDPR (opt-in), CCPA (opt-out), Info-only\r\n- **Preference center**: Granular per-category toggles with cookie audit tables\r\n- **Full color customization**: Background, text, button colors via color pickers\r\n- **Theme presets**: Light and dark themes\r\n- **Brand logo**: Upload custom logo via WordPress Media Library\r\n- **Live preview**: Real-time banner preview in admin as you edit\r\n- **Responsive**: Adapts to mobile viewports, tested on 375px width\r\n- **RTL support**: Arabic, Hebrew, Persian, Urdu, and other RTL languages\r\n- **Consent expiry**: Capped at 180 days per Garante Privacy requirements\r\n- **Revisit widget**: Floating button to reopen preferences after consent\r\n- **Video placeholder**: Blocks YouTube/Vimeo embeds until consent\r\n- **Page exclusions**: Skip banner on specific pages (supports wildcards)\r\n- **Subdomain sharing**: Share consent across subdomains\r\n- **Reload on accept**: Optional page reload after consent\r\n\r\n### Buttons\r\n\r\n- **Accept All** -- grants consent to all categories\r\n- **Reject All** -- denies all non-necessary categories (equal visual weight as Accept)\r\n- **Customize / Settings** -- opens preference center for granular control\r\n- **Read More** -- links to privacy policy (configurable: button or link, nofollow, new tab)\r\n- **Do Not Sell** -- CCPA opt-out button (only in CCPA mode)\r\n\r\n### Cookie Management\r\n\r\n- **Cookie list**: Full CRUD for cookies -- name, domain, duration, description, category, URL pattern\r\n- **Cookie categories**: Necessary, Functional, Analytics, Performance, Advertisement, Uncategorized\r\n- **Per-category prior consent**: Each category has a configurable `prior_consent` flag. Set to OFF for first-party analytics cookies that meet the Garante Privacy exemption (first-party only, aggregated data, anonymized IP, no cross-referencing)\r\n- **Audit table**: Per-category cookie listing embedded in the preference center\r\n- **Multilingual descriptions**: Cookie description and duration stored per-language\r\n\r\n### Cookie Scanner\r\n\r\nA fully local browser-based cookie crawler -- no external scanning service.\r\n\r\n- Discovers pages via sitemap.xml parsing + homepage link extraction\r\n- Scans pages in iframes to detect all cookies\r\n- Configurable scan depth: Quick (10), Standard (100), Deep (1000), Full\r\n- Deduplicates -- never overwrites existing cookie entries\r\n- Scan history with results\r\n\r\n### Open Cookie Database\r\n\r\nIntegrates the [Open Cookie Database](https://github.com/fabiodalez-dev/Open-Cookie-Database) (Apache-2.0) for automatic cookie identification.\r\n\r\n- **Bundled snapshot included** — 2,200+ definitions ship with the plugin for immediate use\r\n- **Manual update** via admin UI button\r\n- **Exact + wildcard matching**: e.g., `_gat_` prefix matches `_gat_UA-12345`\r\n- **Auto-categorize**: One-click bulk categorization\r\n\r\n### Google Consent Mode v2\r\n\r\nFull GCM v2 integration with all required consent signals:\r\n\r\n- `ad_storage`, `analytics_storage`, `functionality_storage`, `personalization_storage`, `security_storage`\r\n- `ad_user_data`, `ad_personalization` (v2 additions)\r\n- **Default: all denied** -- updates to granted on consent\r\n- **Wait for update** -- configurable delay (ms) for slow-loading CMPs\r\n- **URL passthrough** -- pass ad click info even when consent denied\r\n- **Ads data redaction** -- redact ad data when consent denied\r\n\r\n### Google Additional Consent Mode (GACM)\r\n\r\n- Enable/disable toggle\r\n- Configure ATP (Authorized Technology Provider) IDs\r\n- Generates Additional Consent string format: `1~id.id.id...`\r\n\r\n### IAB TCF v2.3 CMP with Global Vendor List\r\n\r\nFull `__tcfapi()` implementation aligned with the IAB Transparency \u0026 Consent Framework v2.3:\r\n\r\n- **Commands**: `ping`, `getTCData`, `addEventListener`, `removeEventListener`, `getVendorList`\r\n- **Global Vendor List (GVL)**: Server-side download and caching of the IAB GVL v3 (1,100+ vendors). Weekly auto-update via WP-Cron, manual update from admin UI\r\n- **GVL Admin Page**: Browse, search, and filter all IAB-registered vendors. Select which vendors your site uses. Paginated table with purpose/feature details\r\n- **Real Vendor Consent**: TC Strings encode actual vendor consent and legitimate interest bits based on user choices and vendor purpose declarations\r\n- **Special Feature Opt-ins**: TCF v2.3 Special Features (precise geolocation, device scanning) mapped from user category consent\r\n- **DisclosedVendors Segment**: Mandatory segment listing all vendors the CMP discloses to users\r\n- **Vendor Legitimate Interest**: Honors user's Right to Object -- LI bits are only set when the user hasn't objected to the corresponding purposes\r\n- **Vendor Consent UI**: Per-vendor toggles in the preference center, with vendor name, purposes, privacy policy link, and cookie retention info\r\n- **TC String**: Full base64url encoding with core segment + DisclosedVendors segment, `euconsent-v2` cookie\r\n- **Cross-frame messaging**: `__tcfapiLocator` iframe + `postMessage` bridge\r\n- **Command queue**: Processes pre-load `__tcfapi.a` queue\r\n- **CMP Stub**: Inline stub responds to `ping` before main script loads (`cmpStatus: 'stub'`)\r\n- **Dynamic config**: ConsentLanguage, publisherCC, gdprApplies, CMP ID, Purpose One Treatment -- all configured from server-side settings\r\n- **GVL file storage**: Cached at `wp-content/uploads/faz-cookie-manager/gvl/vendor-list.json` for frontend access\r\n\r\n#### CMP ID and IAB Registration\r\n\r\nFAZ Cookie Manager works in two modes:\r\n\r\n| Mode | CMP ID | What works | What doesn't |\r\n|------|--------|------------|--------------|\r\n| **Self-hosted** (default) | `0` | Banner, cookie blocking, Google Consent Mode v2, consent logging, all admin features | Ad-tech vendors ignore the TC String (unrecognized CMP) |\r\n| **IAB-registered** | Your ID | Everything above **plus** full TCF vendor chain -- SSPs, DSPs, and ad exchanges read and honor the TC String | Requires [IAB CMP registration](https://iabeurope.eu/cmp-list/) (annual fee) |\r\n\r\n**When do you need a registered CMP ID?**\r\n\r\n- If you run programmatic advertising (header bidding, ad exchanges) and need the buy-side to respect granular vendor consent via the TC String\r\n- If your DPA or legal counsel requires a registered CMP for full TCF vendor-chain support\r\n\r\n**When is self-hosted (CMP ID = 0) sufficient?**\r\n\r\n- You only need GDPR/ePrivacy-oriented cookie consent tooling (banner + script blocking)\r\n- You use Google Consent Mode v2 (GCM uses its own consent signal channel, independent of TCF)\r\n- You don't participate in the IAB programmatic advertising supply chain\r\n\r\nTo set your CMP ID: **Settings \u003e IAB TCF v2.3 \u003e CMP ID**\r\n\r\n### Microsoft Consent Integration\r\n\r\n- **UET Consent Mode**: Sets `ad_storage`/`analytics_storage` defaults to denied, updates on consent\r\n- **Clarity Consent API**: Calls `window.clarity('consent')` when analytics accepted\r\n\r\n### Consent Logging\r\n\r\nStores proof of consent in a local database table for GDPR accountability:\r\n\r\n- **Consent ID**: Unique per-visitor identifier\r\n- **Status**: accepted, rejected, or partial\r\n- **Categories**: JSON map of which categories were accepted/rejected\r\n- **IP hash**: SHA256 hash (privacy-preserving, no raw IPs stored)\r\n- **Pagination** and **search** in admin UI\r\n- **CSV export** with date-stamped filename\r\n- **Retention period**: Configurable (default: 12 months)\r\n\r\n### Pageview Analytics\r\n\r\nBuilt-in analytics dashboard -- no Google Analytics needed for basic metrics:\r\n\r\n- **Events tracked**: pageview, banner_view, banner_accept, banner_reject, banner_settings\r\n- **Dashboard charts**: Daily pageview trend, accept/reject rates\r\n\r\n### Geolocation\r\n\r\nDetects visitor country for geo-targeted banner display:\r\n\r\n- **Detection chain**: Cloudflare \u003e Apache mod_geoip \u003e PHP GeoIP extension \u003e local MaxMind GeoLite2 database\r\n- **Geo-targeting modes**: ALL (everyone), EU (EU/EEA + UK), US only, Custom country list\r\n- **Proxy-aware**: Reads `CF-Connecting-IP`, `X-Forwarded-For`, `X-Real-IP` headers\r\n- **Cached**: 1-hour WordPress transient per IP\r\n\r\n### Multilingual Support\r\n\r\n- **11 bundled languages**: English, German, French, Italian, Spanish, Polish, Portuguese (PT + BR), Hungarian, Finnish, Dutch\r\n- **180+ selectable languages** in the admin configuration\r\n- **Browser language detection**: resolved client-side from `navigator.languages` so full-page/CDN caches cannot serve the wrong language to visitors (see below)\r\n- **Plugin integration**: Polylang, WPML, TranslatePress, Weglot auto-detected (URL-based, always cache-safe)\r\n- **Per-language banner content**: Separate title, description, button text per language\r\n- **RTL auto-detection**: Arabic, Hebrew, Persian, Kurdish, Urdu\r\n\r\n#### Full-page cache and CDN compatibility\r\n\r\nWhen **no URL-based multilingual plugin** (WPML/Polylang/TranslatePress/Weglot)\r\nis installed and **two or more languages** are selected in the admin, the\r\nbanner HTML is rendered server-side in the **site default language** so it\r\nstays safe to cache. A `Vary: Accept-Language` response header is emitted for\r\ncaches that honour it, and the banner is swapped client-side via\r\n`GET /wp-json/faz/v1/banner/{lang}` when the visitor's browser prefers a\r\ndifferent selected language.\r\n\r\nRecommended cache configuration:\r\n\r\n- **Cloudflare (APO / Cache Everything / Cache Rules)**: `Vary` alone is not\r\n  sufficient in these modes. Either keep banner pages off \"Cache Everything\",\r\n  or add a Cache Rule that includes `Accept-Language` in the cache key for\r\n  the affected pages.\r\n- **LiteSpeed Cache**: enable **Cache by language** (Cache → Advanced) or\r\n  exclude banner-bearing pages from HTML caching.\r\n- **WP Rocket**: enable **Cache by language** under Advanced Rules.\r\n- **nginx fastcgi_cache / page caches**: add `$http_accept_language` to the\r\n  cache key.\r\n\r\nEscape hatch — disable browser detection entirely (banner always served in\r\nthe site default language):\r\n\r\n```php\r\nadd_filter( 'faz_disable_browser_language_detection', '__return_true' );\r\n```\r\n\r\nDisable only the `Vary` header (keep client-side detection active):\r\n\r\n```php\r\nadd_filter( 'faz_send_vary_header', '__return_false' );\r\n```\r\n\r\n### Shortcodes\r\n\r\n| Shortcode | Description |\r\n|-----------|-------------|\r\n| `[faz_cookie_table]` | Responsive cookie table grouped by category for policy pages |\r\n| `[cookie_audit]` | Backward-compatible alias |\r\n\r\n**Attributes:** `columns`, `category`, `heading`\r\n\r\n---\r\n\r\n## REST API\r\n\r\nAll endpoints under `faz/v1`. Admin endpoints require authentication (WordPress nonce).\r\n\r\n### Settings\r\n\r\n| Method | Endpoint | Description |\r\n|--------|----------|-------------|\r\n| GET | `/settings` | Get all plugin settings |\r\n| POST | `/settings` | Update settings (merge) |\r\n| POST | `/settings/reinstall` | Recreate missing DB tables |\r\n| POST | `/settings/apply_filter` | Apply WP Internal filter changes |\r\n| POST | `/settings/geolite2/update` | Download/update GeoLite2 database |\r\n| GET | `/settings/geolite2/status` | GeoLite2 database status |\r\n\r\n### Google Consent Mode\r\n\r\n| Method | Endpoint | Description |\r\n|--------|----------|-------------|\r\n| GET | `/gcm` | Get GCM settings |\r\n| POST | `/gcm` | Update GCM settings |\r\n\r\n### Cookies\r\n\r\n| Method | Endpoint | Description |\r\n|--------|----------|-------------|\r\n| GET | `/cookies` | List cookies (filter by category) |\r\n| POST | `/cookies` | Create a cookie |\r\n| GET/PUT/DELETE | `/cookies/{id}` | Read/update/delete a cookie |\r\n| POST | `/cookies/bulk-update` | Bulk update cookies |\r\n| POST | `/cookies/bulk-delete` | Bulk delete cookies |\r\n| POST | `/cookies/scrape` | Lookup names against Open Cookie Database |\r\n| GET | `/cookies/definitions` | Get cookie definitions status |\r\n| POST | `/cookies/definitions/update` | Download/refresh definitions from GitHub |\r\n\r\n### Scanner\r\n\r\n| Method | Endpoint | Description |\r\n|--------|----------|-------------|\r\n| GET | `/scans` | Scan history |\r\n| POST | `/scans` | Start a new scan |\r\n| GET | `/scans/{id}` | Scan details |\r\n| GET | `/scans/info` | Scanner configuration |\r\n| POST | `/scans/discover` | Discover site pages |\r\n| POST | `/scans/import` | Import scan results |\r\n\r\n### Consent Logs\r\n\r\n| Method | Endpoint | Description |\r\n|--------|----------|-------------|\r\n| GET | `/consent_logs` | List logs (paginated, searchable) |\r\n| GET | `/consent_logs/statistics` | Aggregate statistics |\r\n| GET | `/consent_logs/export` | CSV export |\r\n| GET | `/consent_logs/{consent_id}` | Single consent record |\r\n\r\n### Pageviews\r\n\r\n| Method | Endpoint | Description |\r\n|--------|----------|-------------|\r\n| POST | `/pageviews` | Record event (public) |\r\n| GET | `/pageviews/chart` | Pageview chart data |\r\n| GET | `/pageviews/banner-stats` | Banner interaction stats |\r\n| GET | `/pageviews/daily` | Daily pageview breakdown |\r\n\r\n### Banners\r\n\r\n| Method | Endpoint | Description |\r\n|--------|----------|-------------|\r\n| GET | `/banners` | List banners |\r\n| POST | `/banners` | Create a banner |\r\n| GET/PUT/DELETE | `/banners/{id}` | Read/update/delete a banner |\r\n| POST | `/banners/bulk` | Bulk operations |\r\n| GET | `/banners/preview` | Banner preview HTML |\r\n| GET | `/banners/presets` | Theme presets |\r\n| GET | `/banners/configs` | Banner configuration |\r\n\r\n### Global Vendor List (GVL)\r\n\r\n| Method | Endpoint | Description |\r\n|--------|----------|-------------|\r\n| GET | `/gvl` | GVL status (version, vendor count, purposes) |\r\n| GET | `/gvl/vendors` | List vendors (paginated, searchable, filterable) |\r\n| GET | `/gvl/vendors/{id}` | Single vendor details |\r\n| POST | `/gvl/update` | Download/refresh GVL from IAB |\r\n| GET | `/gvl/selected` | Get selected vendor IDs |\r\n| POST | `/gvl/selected` | Save selected vendor IDs |\r\n\r\n### Languages\r\n\r\n| Method | Endpoint | Description |\r\n|--------|----------|-------------|\r\n| GET/POST | `/languages` | Get/update language configuration |\r\n\r\n---\r\n\r\n## Database\r\n\r\nFive custom tables (created on activation):\r\n\r\n| Table | Purpose |\r\n|-------|---------|\r\n| `wp_faz_banners` | Banner configuration and per-language content |\r\n| `wp_faz_cookies` | Cookie definitions (name, category, description, domain, pattern) |\r\n| `wp_faz_cookie_categories` | Cookie categories (necessary, functional, analytics, etc.) |\r\n| `wp_faz_consent_logs` | Visitor consent records with IP hash |\r\n| `wp_faz_pageviews` | Pageview and banner interaction events |\r\n\r\n## Frontend Events\r\n\r\nJavaScript events fired on the `document` for third-party integration:\r\n\r\n| Event | When | Detail |\r\n|-------|------|--------|\r\n| `fazcookie_consent_update` | User accepts/rejects/saves | `{ accepted: ['slug', ...], rejected: ['slug', ...] }` |\r\n| `fazcookie_banner_loaded` | Banner is displayed | -- |\r\n\r\n### Consent Cookie Format\r\n\r\nCookie name: `fazcookie-consent`\r\n\r\nValue format: `consentid:{base64},consent:yes,action:yes,necessary:yes,functional:no,analytics:no,marketing:no,performance:no`\r\n\r\n## WordPress Hooks\r\n\r\n### Filters\r\n\r\n| Filter | Description |\r\n|--------|-------------|\r\n| `faz_cookie_domain` | Override the consent cookie domain |\r\n| `faz_allowed_html` | Customize allowed HTML tags in banner |\r\n| `faz_current_language` | Override detected language |\r\n| `faz_language_map` | Add language code normalization mappings |\r\n| `faz_registered_admin_menus` | Register additional admin menu items |\r\n\r\n### Actions\r\n\r\n| Action | Description |\r\n|--------|-------------|\r\n| `faz_after_activate` | After plugin activation/upgrade |\r\n| `faz_after_update_settings` | After settings are saved |\r\n| `faz_after_update_cookie` | After cookies are bulk-updated |\r\n| `faz_reinstall_tables` | Trigger table recreation |\r\n| `faz_clear_cache` | Trigger cache flush |\r\n\r\n---\r\n\r\n## Changelog\r\n\r\n### 1.13.6\r\n- **New**: blocker-template parity with `Known_Providers`. Every provider the runtime already auto-blocks (143 services — Google Analytics, Adobe, Plausible, Clarity, Mixpanel, Segment, Stripe, Mailchimp, Klaviyo, HubSpot, Pinterest, Snapchat, Reddit, Outbrain, Yandex, etc.) now appears in WP Admin → Cookies → \"Add from template\". The picker grows from 11 to 142. Privacy contract unchanged — this is a UI-discovery fix.\r\n- **Internal**: the 131 new templates were generated from `includes/data/known-providers.json` so admin picker and runtime blocker stay in sync.\r\n\r\n### 1.13.5\r\n- **New**: Matomo (Piwik) blocker template — selectable as an analytics tool in Cookies → Blocker Templates. Covers self-hosted Matomo, Matomo Cloud, and Matomo Tag Manager, plus the full `_pk_*`, `MATOMO_SESSID`, and `mtm_consent*` cookie family. (Matomo was already auto-detected by the runtime script blocker; this just exposes the entry in the admin picker so it's discoverable.)\r\n\r\n### 1.13.4\r\n- **Fix**: `wp_localize_script` / translation payloads (`{handle}-js-extra`, `{handle}-js-translations`) for FAZ scripts now also carry the 5 cache opt-out attrs. Those inline tags don't travel through `script_loader_tag`; added a hook on `wp_inline_script_attributes` (WP 5.7+) so the cache-plugin opt-out applies to them too. Closes a guarantee gap that LiteSpeed Guest Mode was exposing.\r\n\r\n### 1.13.3\r\n- **Fix**: banner invisible on first paint when LiteSpeed Cache *Delay JS* had a hand-added entry mentioning `faz-cookie-manager` without the full `wp-content/plugins/` prefix — the 1.13.2 path-anchored scrubber was strict-anchored and skipped those entries; 1.13.3 also matches `faz-cookie-manager` as a complete token while still leaving third-party companion names like `my-integration-faz-cookie-manager-compat.js` untouched. Reported by gooloo.de.\r\n\r\n### 1.13.2\r\n- **Fix**: GDPR Strict preset \"Customize\" button (light-blue text on dark-blue background) — the `classic` template CSS had `color: #1863dc` hardcoded instead of reading the preset's `--faz-settings-button-color`, and `border-color` pointed at the text-colour variable instead of its own. Pattern now matches the other template variants.\r\n- **Fix**: banner invisible on LiteSpeed Guest Mode installs — added the missing `litespeed_optm_gm_js_exc` filter so Guest Mode's separate JS exclude list also recognises our scripts; first-visit paint restored on Guest-Mode-enabled sites.\r\n- **Fix**: alt-asset mode (`faz-fw` alias) children (`faz-fw-gcm`, `faz-fw-tcf-cmp`, `faz-fw-a11y`) now correctly tagged with the cache-plugin opt-out attributes; 1.13.1 missed them because the handle list was hardcoded.\r\n- **Fix**: `litespeed_optm_js_delay_inc` scrubbing now path-anchored (`plugins/faz-cookie-manager/`) so third-party integration entries are never collaterally removed.\r\n- **New**: `faz_auto_exclude_cache_plugins` filter for site admins who want to disable the automatic cache-plugin exclusion block (default `true`).\r\n\r\n### 1.13.1\r\n- **Auto-exclude FAZ scripts from cache plugins' Delay JS** — LiteSpeed Cache, WP Rocket, Autoptimize, SG Optimizer, Hummingbird, Cloudflare Rocket Loader and W3 Total Cache all default to deferring every JS file until first user interaction, which kept the consent banner dormant on page load and let trackers fire the moment the user scrolled. The plugin now adds `data-no-defer data-no-optimize data-no-minify data-cfasync=\"false\" data-ao-skip` to every FAZ `\u003cscript\u003e` and hooks the matching pattern-based exclude filters so admins no longer need to configure a thing.\r\n\r\n### 1.13.0\r\n- **Fix (#80)**: per-service consent cookie stays under the browser's 4 KB limit — `_fazSetInStore` omits `svc.\u003cid\u003e` entries whose value matches the category (the frontend loader already falls back to the category when absent). Previously a ~160-service install made every \"Save My Preferences\" click a no-op because the oversized write was silently dropped.\r\n- **Fix (#78)**: scanner `discover_urls` places recently-modified pages in `priority_urls` so they're exempt from the client-side early-stop threshold — freshly-edited posts could previously be skipped on large sites.\r\n- **Fix**: `shred_non_consented_cookies()` honours the frontend whitelist payload (was only respected on the first page load, then neutralized on every `send_headers`).\r\n- **Fix**: whitelist pattern match is unidirectional with a minimum-length guard — entering `\"js\"` or `\"com\"` no longer whitelists nearly every provider.\r\n- **Fix**: preference center focus-retry timers are cancelled on close (no more focus theft after rapid open/close).\r\n- **Fix**: dynamic scripts preserve their original `type` (`module`, etc.) through the block/unblock round-trip via `data-faz-original-type`.\r\n- **Internal**: provider-matrix fixture serialises hit increments under `flock`, `fazApiPut` uses `X-HTTP-Method-Override` for nginx/Apache/php -S portability, permalink-agnostic scanner discover predicate, deduped `get_priority_urls` WP_Query.\r\n\r\n### 1.12.1\r\n- **Fix**: LiteSpeed Cache cookies (`_lscache_vary`, `_litespeed_*`) added to internal whitelist\r\n\r\n### 1.12.0\r\n- **Security audit**: closed all findings from 20-agent code audit (H2-H5, M1-M28)\r\n- **data: URI blocking**: decoded payload matched against provider patterns (PHP + JS)\r\n- **Uppercase HTML tags**: `strpos` → `stripos` in output buffer guards\r\n- **Consent logging**: throttle fix for empty consent_id, URL credential stripping, UA hashing\r\n- **TCF/IAB v2.3**: `buildConsentArtifacts`, Purpose 1 treatment, euconsent-v2 cleanup\r\n- **Accessibility**: extended focus trap, summary support, localized aria-labels\r\n- **Performance**: `faz_settings` memoized, N+1 eliminated, `faz_current_language()` cached\r\n- **Plugin Check**: 0 ERRORS — all escaping, WP_Filesystem, and ABSPATH issues resolved\r\n- **Tests**: 35+ new E2E tests (category blocking, audit regressions, session fixes)\r\n- **DB migration 3.4.1**: banner table indexes for existing installs\r\n\r\n### 1.11.3\r\n- **New: WP 5.7+ `wp_inline_script_tag` filter** — intercepts inline scripts added via `wp_add_inline_script()` before the output buffer. Backward compatible (WP \u003c 5.7 uses the OB fallback).\r\n- **New: returning visitor unblock retry** — `_fazUnblock()` retries at multiple delays (250ms, 1s, 2s) + load event so late-rendered blocked scripts are always restored.\r\n- **Fix: WordPress Plugin Check errors** — resolved all `OutputNotEscaped`, `MissingTranslatorsComment`, and `NoExplicitVersion` findings for wp.org submission compliance.\r\n- **Fix: inline script whitelist bypass** — `is_whitelisted()` now checks only tag attributes, not the inline body.\r\n- **Refactor: `_fazBuildRestoredScript()` helper** — deduplicated script-cloning logic from `_fazUnblockServerSide()`.\r\n\r\n### 1.11.2\r\n- **Fix: preference center invisible on dark design presets** — all 5 presets now include full `preferenceCenter`, `categoryPreview` and `optoutPopup` color palettes (background, text, buttons, toggle states). Previously only the banner bar was styled.\r\n- **Fix: TypeError crash on ChromeOS / PMP-exempt members** — `_fazRenderBanner()` null guard prevents crash when the banner template element is absent (PMP-exempt members, empty cache).\r\n- **Fix: `applyDesignPreset()` deep-replaces preference center and optout popup config** — the old cherry-pick missed toggle states and left stale values across preset switches.\r\n- **Fix: `const _fazGsk = true;` → `var`** for broader browser compatibility in the WP Consent API inline script.\r\n- **Fix: removed `#000000` → transparent skip in template CSS** — High Contrast preset buttons now render as black instead of falling back to the default blue.\r\n- **Internal: `normalizeBannerConfig()`, law-specific sanitization defaults, 6 new E2E regression tests.**\r\n\r\n### 1.11.1\r\n- **Fix: banner reappears on every page load (critical)** — the `fazcookie-consent` cookie was written without URL-encoding, so on the next pageview the naive `document.cookie` splitter lost the `,` and `:` separators, `rev` couldn't be extracted, and `isConsentCookieStale()` wiped the cookie every time. URL-encode on write, two-pass decode on read. Reported by a live publisher running 1.11.0 in production.\r\n- **Fix: PMP `exempt_levels` setting didn't persist (critical)** — `Settings::sanitize()` was coercing the CSV input `\"2, 3\"` to `[]` before `sanitize_option()` could parse it. Excluded keys are now dispatched to their per-key handler first. Without this fix the entire Paid Memberships Pro integration was silently non-functional.\r\n- **Fix: Non-personalized ads fallback also forces `ad_user_data` and `ad_personalization` to `denied` in the region-default code path** (not just in `buildConsentState()`). Prevents the first-page `gtag(\"consent\", \"default\", …)` from being more permissive than the post-\"reject all\" state.\r\n- **Fix: PMP auto-grant cookie wrote `consent:accepted` but `script.js::_fazUnblock()` gates on `consent:yes`** — exempt members had their scripts server-side-unblocked but client-side-re-blocked. Aligned the token and pinned the literal in a regression assertion.\r\n- **Fix: `setAdditionalConsent(null)` no longer fires during the stale-revision window in `fazcookie_consent_update`** — would otherwise clobber the live GACM provider list with an empty `\"1~\"`.\r\n- **Fix: Settings page race condition** — if `loadSettings()`'s GET resolved after `invalidateConsents()` bumped `consent_revision`, the form silently reverted the counter. Added a monotonic `settingsRequestId` guard.\r\n- **Fix: Cross-domain consent forwarding regex accepts base64** — old allowlist rejected `+`, `/`, `=`; forwarded consents from multi-domain setups were silently dropped.\r\n- **Fix: `wca.js` and `microsoft-consent.js` requested `.min.js` that does not exist** — those scripts are not in the `build:min` pipeline but reused `$suffix` from `script.js`. On installs with `script.min.js`, WP Consent API and Microsoft UET/Clarity consent integration 404'd. Suffix is now computed per-file.\r\n- **Fix: PMP auto-grant cookie filtered internal/admin categories** — `wordpress-internal` (wp-settings-*, wordpress_logged_in_*) and invisible categories are no longer declared in a visitor's consent record.\r\n- **Fix: changelog wording on NPA fallback** — clarified that with `ad_storage = granted` advertising identifiers can still be written for frequency capping / fraud detection; what NPA removes is profiling and ad-user-data signals, not all cookies.\r\n- **New: Czech (cs_CZ) translation** — 441 fully translated strings (frontend banner, categories, admin UI, shortcodes) contributed by Vaclav. Ships `languages/faz-cookie-manager-cs_CZ.po` and `.mo`.\r\n- **Refactor: `faz_get_cookie_domain()` is now the single source of truth** — `Frontend::get_cookie_domain()` delegates to it; the public-suffix-aware TLD list is no longer duplicated between client-facing and server-facing code paths.\r\n\r\n### 1.11.0\r\n- **New: Non-personalized ads fallback for Google Consent Mode** — new setting in `GCM → Advanced`. When a visitor denies marketing consent, `ad_storage` stays `granted` while `ad_user_data` and `ad_personalization` are forced to `denied`. This is the Google-sanctioned configuration for serving non-personalized ads to visitors who reject the banner, so publishers still earn ad revenue on those pageviews. Important: with `ad_storage = granted`, advertising cookies and persistent identifiers may still be written and read on the visitor's device — what changes is that those identifiers are not used for building user profiles or personalizing creative (`ad_user_data`/`ad_personalization` being denied). Disabled by default to preserve previous behaviour. See [Google AdSense docs](https://support.google.com/adsense/answer/13554116).\r\n- **New: Force re-consent (consent versioning)** — new `Settings → Force re-consent` card with an \"Invalidate all consents\" button. Clicking it bumps `faz_settings.general.consent_revision`; returning visitors whose stored cookie carries a lower revision see the banner again on their next visit. Useful after changing AdSense/GTM settings or adding new tracking services. The cookie format is backward-compatible: cookies from \u003c 1.11.0 have no `rev` key and are NOT invalidated automatically on upgrade — only once the admin explicitly clicks the button.\r\n- **New: Paid Memberships Pro integration (Pay-or-Accept / PUR model)** — new optional integration. When PMP is installed, a `Settings → Paid Memberships Pro integration` card becomes visible. Admin enters a comma-separated list of PMP level IDs; members of those levels bypass the cookie banner entirely and have consent auto-granted across all categories via a server-side cookie set on `init`. Non-paying visitors follow the standard consent flow. No-op when PMP is not active. Third-party code can override the exemption via the `faz_pmp_user_exempted` filter.\r\n- **Fix: GCM race condition on revisit** — `gcm.js` now emits `gtag(\"consent\", \"default\", …)` with the cookie-derived granted states directly for returning visitors, instead of `default denied → update granted`. This removes the brief window in which AdSense/GTM would fire the first ad request while consent was still `denied`. Fixes the user report where ads only loaded \"after a couple of refreshes or a manual re-accept\".\r\n- **Fix: `wait_for_update` default incoherence** — admin UI showed `500` as the default, PHP defaults had `2000`. Aligned both to 500 ms (Google's recommended minimum).\r\n\r\n### 1.10.2\r\n- **Fix: preference center text colour on dark-theme host sites** (follow-up to [#57](https://github.com/fabiodalez-dev/FAZ-Cookie-Manager/issues/57)) — the 1.10.1 fix that added a solid default background to `.faz-preference-center` exposed a pre-existing problem: several rules inside the preference center used `color: inherit`, which on sites with a dark theme (body text set to a light colour) inherited that light colour. The result was unreadable \"light on white\" text inside the now-white modal. Locked the text colour to `var(--faz-detail-color, #212121)` on `.faz-preference-center`, `.faz-preference`, `.faz-preference-header`, `.faz-footer-wrapper`, `.faz-preference-body-wrapper`, `.faz-accordion-wrapper` and the description paragraphs. The default is dark regardless of host theme, and users can still override the colour from the banner editor because the CSS variable is fed from the stored banner config.\r\n- **Test: new E2E regression for the dark-theme scenario** — injects a dark-theme stylesheet on the host site (`html, body, .wp-site-blocks { background: #0f0f10 !important; color: #e6e6e6 !important }`), opens the preference center, and asserts every text-bearing element (`.faz-preference-center`, `.faz-preference-header`, `.faz-preference-title`, description paragraphs, accordion buttons) has a dark computed `color` instead of the injected light one.\r\n\r\n### 1.10.1\r\n- **Fix: preference center transparent background on classic template** — When the banner type is \"full-width + pushdown\" (which internally maps to the `classic` template), clicking the *Customize* button opened a preference center with no background colour. Root cause: `.faz-preference-center` used `background-color: inherit`, and the classic template wraps it in `.faz-preference-wrapper` (not `.faz-modal`), so there was no ancestor providing a colour — the modal ended up fully transparent. Replaced the `inherit` rule with `background-color: var(--faz-detail-background-color, #ffffff)` so the default is always a solid background, regardless of which template variant is active. Reported as [issue #57](https://github.com/fabiodalez-dev/FAZ-Cookie-Manager/issues/57).\r\n- **Test: E2E regression for issue #57** — switches the banner to `classic` + `pushdown`, opens the preference center on the frontend, and asserts the computed `background-color` of `.faz-preference-center` is not `rgba(0, 0, 0, 0)` / `transparent`. Canary for future regressions.\r\n\r\n### 1.10.0\r\n- **German (de_DE) translation** — ships `languages/faz-cookie-manager-de_DE.po` and `.mo` covering `[faz_cookie_policy]`, `[faz_cookie_table]`, cookie category names and common banner labels. Fixes the gooloo.de user report where the Cookie Policy shortcode stayed in English on a German-only site because the plugin had no `de_DE.mo` to load.\r\n- **Admin JavaScript i18n infrastructure** — 128 localized keys exposed via `fazConfig.i18n.*`, organized in 8 namespaces (cookies, banner, settings, GCM, consent logs, languages, GVL, import/export, dashboard). Every admin page JS now uses a shared `__(key, fallback)` helper.\r\n- **WordPress.org submission assets** — new `.wordpress-org/` directory with 10 publish-ready screenshots (banner, preference center, dashboard, banner editor, cookies, IAB TCF GVL, consent logs, GCM, languages, settings), a full `PUBLISHING-GUIDE.md` covering the submission checklist, SVN workflow, asset sizing and reviewer Q\u0026A, plus a reproducible Playwright capture script at `scripts/capture-wporg-screenshots.mjs`.\r\n- **New FAQ entries** in `readme.txt`: telemetry, minified JS source and data removal on uninstall — the three questions wp.org reviewers always ask.\r\n- **`.distignore` / release ZIP hardening** — excludes `.wordpress-org/`, `assets/`, `composer.json`, `composer.lock`, `tsconfig.json`. Distribution ZIP shrunk from 7.0 MB to 5.6 MB (of which ~2.7 MB is the intentional bundled Open Cookie Database).\r\n- **Fix: cookie definitions metadata normalization** — `Cookie_Definitions::get_meta()` now merges stored meta over a defaults array, so legacy installs upgrading from \u003c 1.9 without the `source` field no longer send the UI down the wrong \"downloaded vs. bundled\" branch.\r\n- **Fix: `META_KEY` autoload flag** — `update_option( self::META_KEY, …, false )` matches the `OPTION_KEY` pattern, keeping metadata out of the autoload bucket.\r\n- **Fix: `importFailed` i18n string** — now contains the `%s` placeholder expected by `import-export.js`, so the actual error detail is surfaced instead of being silently swallowed by `String.replace('%s', …)`.\r\n- **Fix: GVL admin page fully localized** — 8 previously hardcoded English strings in `admin/views/gvl.php` (heading, buttons, aria labels, placeholder, \"All purposes\", \"Select all on this page\", \"Save Selection\") are now wrapped with `esc_html_e` / `esc_attr_e`.\r\n- **Fix: GVL REST API error message** — `'vendor_ids must be an array.'` is now translatable via `__()`.\r\n- **Fix: JS i18n payload** — replaced 128 `esc_html__()` calls inside the `fazConfig.i18n` array with plain `__()`. HTML-escaped strings like `\u0026quot;` were leaking into the UI because JS `.textContent` and `FAZ.notify()` don't interpret HTML entities.\r\n- **Fix: fully localized `gvl.js` and `settings.js` templates** — \"Saved N vendor(s)\", \"GVL updated vX (N vendors)\" and \"DB file (size) — Last updated: date\" lines (previously mixed English fragments with localized strings).\r\n- **Test: new E2E regression for the gooloo.de scenario** — sets `WPLANG=de_DE`, creates a page with `[faz_cookie_policy]`, asserts German strings render (`Was sind Cookies`, `Notwendige Cookies`, `Cookies verwalten`) and the English fallbacks do **not**. Canary for future regressions if anyone deletes `de_DE.mo` by mistake.\r\n- **Test: E2E teardown hardening** — `pr-regression.spec.ts` WPLANG restore uses the shared `completeAdminLogin` helper and `WP_ADMIN_USER`/`WP_ADMIN_PASS` env variables instead of hardcoded `admin`/`admin`.\r\n- **7 rounds of CodeRabbit review addressed**.\r\n\r\n### 1.9.2\r\n- **Fix: language settings controller** — settings API no longer re-injects the default language into the selected list on every read, fully fixing the \"English always comes back\" bug for non-English sites\r\n\r\n### 1.9.1\r\n- **Fix: default language uses site locale** — `faz_default_language()` now falls back to WPLANG (e.g. `de_DE` → `de`) instead of hardcoded `'en'`, so German/French/etc.-only sites work correctly without English being forced back\r\n- **Fix: theme link color bleed** — added CSS reset (`color:inherit`) on `#faz-consent a,button` to prevent Divi, Elementor, and other page builder themes from overriding banner button colors\r\n\r\n### 1.9.0\r\n- **WCAG 2.2 accessibility** — new `a11y.js` with `role=\"dialog\"`, `aria-modal`, `aria-labelledby`, heading hierarchy (`\u003ch2\u003e`/`\u003ch3\u003e`), `role=\"switch\"` on toggles, dynamic checkbox labels, and Escape key support (contributed by Yard Digital Agency)\r\n- **CSS custom properties** — all banner inline styles replaced with `--faz-*` CSS vars for CSP compatibility and easy theme customization (contributed by Yard Digital Agency)\r\n- **Dutch language** — 573 fully translated strings (contributed by Yard Digital Agency)\r\n- **Admin UI refresh** — modern design system, real-time iframe-based banner preview, design presets\r\n- **Settings save fix** — `array_merge` no longer accumulates duplicates on repeated saves\r\n- **Blocker templates auto-save** — clicking a template now persists rules immediately\r\n- **Security hardening** — SSRF protection on scanner redirects, path traversal sanitization, CSS var name sanitization, ABSPATH guard on autoloader\r\n- **Error handling** — banner API returns `WP_Error` on DB failures (create, update, delete, bulk)\r\n- **Focus management** — preference center restores focus to trigger element on close (WCAG 2.4.3)\r\n- **Performance** — a11y.js loaded in footer (non render-blocking), `.faz-accordion-heading` CSS normalized across all template types\r\n- **10 rounds of CodeRabbit review** — 68+ findings addressed\r\n- **155+ E2E tests** across admin, frontend, scanner, a11y, and blocking flows\r\n\r\n### 1.8.0\r\n- **WooCommerce-aware scanner** — auto-discovers shop, product, cart, checkout, my-account pages for comprehensive cookie detection\r\n- **Scanner Debug Mode** — logs every categorization decision, downloadable from admin\r\n- **OCD auto-download** — 7400+ cookie definitions downloaded on activation\r\n- **\"Remove all data on uninstall\"** — opt-in setting (default OFF) prevents accidental data loss\r\n- **Admin nav bar translated** — all labels now translatable via .po/.mo\r\n- **Inferred cookies use site domain** — no more `googletagmanager.com` as cookie domain\r\n- **Auto-categorize serialized** — no more 503 rate limiting on shared hosts\r\n- **Server-scan always merges** — catches LiteSpeed/WP Rocket deferred scripts\r\n\r\n### 1.7.2\r\n- **Per-service cookie shredding** — denied services now have their cookies deleted even when the parent category is consented\r\n- **Scanner 3-tier lookup** — integrates Open Cookie Database (1400+ entries) as fallback, drastically reducing \"uncategorized\" cookies\r\n- **Blocker templates create cookies** — applying a template now adds cookies to the DB, not just blocking rules\r\n- **French translation** — complete `fr_FR` locale with 579 translated strings (thanks @pascalminator)\r\n- **Cookie_Database expanded** — 40 → 64 entries including `_GRECAPTCHA`, GA Classic, YouTube, Stripe, and more\r\n- **i18n fixes** — scanner uses default language, backend preserves all translation keys, shortcode category names use `localize_category_name()`\r\n- **18 new E2E tests** — comprehensive regression coverage for PRs #39, #41, #44\r\n- **Scanner LiteSpeed/cache compatibility** — reads `data-src` and `data-litespeed-src`, server-side scan always merges, description enrichment from OCD\r\n- **Cache flush after scan** — fixes empty cookie table after scan on sites with object cache\r\n\r\n### 1.7.1\r\n- **Admin performance** — 50-68% faster backend navigation (cache fix, N+1 query, REST preloading)\r\n- **User-configurable whitelist** for scripts/network requests with 11 default API patterns (fixes #40)\r\n- **Google Maps TypeError fix** — type guards on all DOM-facing blocking functions (fixes #35)\r\n- **ClassicPress compatibility** — Gutenberg guard, `wp_date` → `date_i18n`\r\n- **Banner type persistence** — fixed incorrect classic↔banner mapping in admin JS\r\n\r\n### 1.7.0\r\n- **26 new features** — scheduled scanning, consent stats, cookie policy shortcode, geo-IP banner, visual placeholders, multisite, Gutenberg blocks (3), design presets (5), bot detection, GTM data layer, WP privacy tools, dashboard widget, cross-domain consent, cookie deletion, age protection, anti-ad-blocker, per-service consent, import/export, AMP consent, content blocker templates (10), WP-CLI commands, system status, TranslatePress/Weglot compat, unmatched vendor notification\r\n- **Category editor** — edit category names/descriptions from admin (fixes #38)\r\n- **Custom CSS** — banner custom CSS now saves and renders (fixes #37)\r\n- **Per-service consent** — individual service toggles override category consent\r\n- **Security** — import sanitization, CodeQL DOM XSS resolved, AMP guards, per-service cookie shredding, transactions with ROLLBACK\r\n- **34 new E2E tests** for all features + deep-flow coverage\r\n\r\n### 1.6.1\r\n- **Security hardening** — GCM settings sanitisation (whitelist keys, validate values), pageview endpoint HMAC token, scanner SSRF prevention (block private IPs), filter data sanitisation, CSS injection fix\r\n- **Bug fixes** — switch fallthrough, null guards for CCPA/preference/readmore handlers, deprecated `event.which` → `event.key`, double DOM query fix, `.map()` → `.forEach()` cleanup\r\n\r\n### 1.6.0\r\n- **WooCommerce compatibility** — auto-whitelists WooCommerce core + payment gateway scripts on checkout/cart pages\r\n- **Complete admin i18n** — all 387 admin UI strings wrapped in WordPress translation functions\r\n- **Italian translation** — complete `it_IT` (386 strings) with formal register and GDPR terminology\r\n- **Contextual help text** — `.faz-help` descriptions on all settings pages (fixes #27)\r\n- **Do Not Sell text colour picker** — dedicated colour control for CCPA opt-out link (fixes #34)\r\n- **Pageview tracking opt-in** — new toggle in Settings (default: off for stricter privacy defaults)\r\n- **Customize overlay fix** — removed nonce from public REST endpoints; stale nonces on cached pages caused 403 (fixes #35)\r\n- **Consent log integrity** — HMAC origin token prevents external spoofing\r\n- **Subdomain cookie sharing** — fixed for `.co.uk`, `.com.au`, `.co.jp` and 30+ multi-level TLDs\r\n- **PCRE fail-secure** — strips scripts on regex error instead of serving unblocked\r\n\r\n### 1.5.2\r\n- **Security \u0026 mixed-content fixes** — auto-repair cached banner template on HTTPS, sanitise inline CSS values, harden URL parsing\r\n- **Plugin lifecycle E2E tests** — upgrade and fresh-install paths with full category verification\r\n\r\n### 1.5.1\r\n- **Link color fix** — link colour picker now applies to all visible links including Cookie Policy/Read More link\r\n- **Brand logo 404** — moved `cookie.png` to `frontend/images/` with DB migration for existing installs\r\n\r\n### 1.5.0\r\n- **Link text colour picker** — new colour control in Banner Colours tab\r\n- **E2E test suite for banner settings** — 21 Playwright tests covering all banner tabs\r\n\r\n### 1.4.1\r\n- **ClassicPress polyfill fix** — WP 4.9 inline script compatibility\r\n\r\n### 1.4.0\r\n- **5-layer script blocking** — WP hooks, content filters, output buffer, client-side interceptors, cookie shredding\r\n- **Known Providers database** — 147+ services with 500+ URL/script patterns\r\n- **Video/social embed placeholders** — YouTube, Vimeo, Facebook, Instagram, Twitter/X consent placeholders\r\n- **Custom blocking rules** — admin UI for user-defined patterns per category\r\n- **Network interception** — XHR, fetch, sendBeacon requests to blocked providers silently dropped\r\n\r\n### 1.3.0\r\n- **Incremental cookie scans** — only re-scans modified pages\r\n- **Scan progress UI** — real-time progress bar with ETA\r\n- `advertisement` category renamed to `marketing` across the entire plugin\r\n\r\n### 1.2.0 – 1.2.1\r\n- Dual-guardrail consent throttle, proxy header trust filter\r\n- CSV export fix, consent log \"rejected\" status fix\r\n- Security: prototype pollution guard, DOM XSS prevention\r\n- Playwright E2E test suite (11 tests), Composer/Packagist support\r\n\r\n### 1.1.0\r\n- **IAB TCF v2.3** with Global Vendor List, vendor consent UI, TC String encoding\r\n- **GVL Admin Page** — browse, search, filter 1,100+ IAB vendors\r\n- Google Consent Mode v2, Microsoft UET/Clarity consent, local consent logging, cookie scanner\r\n\r\n### 1.0.0\r\n- Initial release — based on the GPL-licensed CookieYes v3.4.0 codebase, fully de-branded, cloud-free, and self-hosted\r\n\r\n## Translations\r\n\r\nFAZ Cookie Manager is fully translatable. All admin and frontend strings use WordPress i18n functions (`__()`, `_e()`, `esc_html__()`) with the `faz-cookie-manager` text domain.\r\n\r\n**How to translate:**\r\n\r\n1. Use the included `.pot` file at `languages/faz-cookie-manager.pot` as a template\r\n2. Create a `.po` file for your language (e.g., `faz-cookie-manager-it_IT.po`) using [Poedit](https://poedit.net/) or any gettext editor\r\n3. Compile it to `.mo` and place both files in the `languages/` folder\r\n4. WordPress will automatically load the translation matching your site language\r\n\r\nThe banner content (title, description, button labels) is configured separately in the admin UI under **Banner → Content** and supports per-language customisation via the **Languages** module.\r\n\r\n## Author\r\n\r\n**Fabio D'Alessandro** -- [fabiodalez.it](https://fabiodalez.it/)\r\n\r\n## Support the Project\r\n\r\nIf FAZ Cookie Manager is useful to you, consider buying me a coffee. Your support helps fund IAB CMP registration and continued development.\r\n\r\n[![Buy Me A Coffee](https://img.shields.io/badge/Buy%20Me%20A%20Coffee-support-yellow?style=for-the-badge\u0026logo=buy-me-a-coffee)](https://buymeacoffee.com/fabiodalez)\r\n\r\n## License\r\n\r\nGPL-3.0-or-later. See [LICENSE](LICENSE) for full text.\r\n\r\nCookie definitions powered by [Open Cookie Database](https://github.com/jkwakman/Open-Cookie-Database) (Apache-2.0).\r\n","funding_links":["https://buymeacoffee.com/fabiodalez"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffabiodalez-dev%2Ffaz-cookie-manager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffabiodalez-dev%2Ffaz-cookie-manager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffabiodalez-dev%2Ffaz-cookie-manager/lists"}