=== AlpineConsent ===
Contributors: alpineconsent
Tags: cookie consent, gdpr, privacy, consent management, cookie banner
Requires at least: 6.0
Tested up to: 6.6
Requires PHP: 8.0
Stable tag: 0.6.37
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Lean, EU-native cookie consent and compliance widget for WordPress.

== Description ==

AlpineConsent is a lightweight cookie consent management platform (CMP), built and hosted in Austria/Germany. It helps WordPress sites comply with the GDPR, the Austrian TKG 2021, and the German TDDDG, without the weight of typical enterprise consent plugins.

The plugin enqueues the real AlpineConsent banner — granular consent categories (necessary/preferences/statistics/marketing), prior-blocking of scripts and iframes, Google Consent Mode v2 — and holds any script you assign a category to under its own AlpineConsent menu until a visitor grants it. A script left unassigned loads normally, so activating the plugin never breaks a site by default.

Scripts are found for you automatically — no need to dig through theme or plugin code for a WordPress "handle." As visitors load your pages (or immediately, via the "Scan site now" button), every tracked script is listed with a suggested category already filled in, matched against a real, curated database of thousands of known cookies and providers. You just confirm or change it. That same scan also reads the cookies your pages actually set, showing each one's real description, retention period, and data controller on a separate Cookies tab.

The banner's layout (bar top/bottom, floating, or modal), title/description text, and button set are all configurable on the Banner tab — buttons can be shown as buttons or plain links, reordered, and you can add your own Privacy Policy/Cookie Policy/Imprint links (with a one-click autofill for WordPress's own Privacy Policy page). A small "Powered by AlpineConsent" badge shows on the free plan.

The banner's language auto-detects: if you run WPML or Polylang, it follows that visitor's own detected language dynamically — whatever languages your site is actually configured for, not a fixed list — otherwise it follows your site's own WordPress language setting. Every button, category label, and badge, in every one of your site's languages, is fully editable on the Banner tab's "Button & banner text" section — pre-filled with a suggested translation as a starting point, or plain English when we don't have one yet.

Not yet implemented: automatic theme-matching with your site's own colors/fonts, consent logging, and languages beyond German/English.

== External services ==

This plugin connects to the following external services, both operated by AlpineConsent itself:

1) **Automatic update checks** (always, no action needed from you)
This plugin isn't distributed through the WordPress.org Plugin Directory yet, so it checks for new versions using AlpineConsent's own self-hosted release server rather than wordpress.org's. On a normal update-check cycle, a request is sent to:
`https://releases.alpineconsent.com/wordpress-plugin/latest-release`
When an update is actually installed, the plugin also downloads the update package and its cryptographic signature from that same release server and verifies the signature before installing — an unsigned or tampered package is refused. No personal or visitor data is sent — only what any plain HTTP request implicitly includes (server IP, user agent). See [AlpineConsent's Privacy Policy](https://alpineconsent.com/privacy).

2) **Connect to AlpineConsent account** (only if you click "Connect to AlpineConsent" under Settings)
Links this WordPress site to your AlpineConsent account so the plugin knows your real plan — this only ever happens if you start the flow yourself. Your site's domain and a one-time authorization code are sent to:
`https://api.alpineconsent.com/connect/exchange`
See [AlpineConsent's Privacy Policy](https://alpineconsent.com/privacy) and [Terms of Service](https://alpineconsent.com/terms).

3) **"View details" popup images** (only if you click "View details" on this plugin in your Plugins list)
The popup's banner image is loaded directly by your own browser from AlpineConsent's public documentation site:
`https://docs.alpineconsent.com/docs/assets/wordpress-plugin/`
No data about your site is sent — this is a plain image request, the same as any `<img>` tag on any web page.

No visitor-facing data — cookies, consent choices, or page content — is sent to AlpineConsent by this plugin. The consent banner and script-blocking run entirely in the visitor's own browser and your own WordPress database. "Scan site now" fetches your own site's own pages locally (via `wp_remote_get()`) — nothing is sent to AlpineConsent for that either.

== Frequently Asked Questions ==

= Does this plugin send my visitors' data to AlpineConsent? =

No. Consent choices and script-blocking happen entirely in the visitor's browser and your own WordPress database. See "External services" above for the two things this plugin does talk to AlpineConsent for — an automatic version check, and (only if you choose to) linking your site to your account.

= Will this break my site if I just activate it? =

No — a script only gets held for consent once you explicitly assign it a category under the AlpineConsent menu. An unassigned script keeps loading exactly as it did before you installed the plugin.

= Do I need an AlpineConsent account to use this? =

No. The plugin is fully functional standalone — connecting an account (Settings -> Connect to AlpineConsent) is optional and only relevant if you're on a paid plan.

= What happens on the free plan? =

The banner, automatic script/cookie discovery, and manual categorization all work fully. A small "Powered by AlpineConsent" badge shows on the banner; it's removed once your site is connected to a paid plan.

== Installation ==

1. Upload the `wordpress-plugin` directory to `/wp-content/plugins/alpineconsent`, or install via the WordPress plugin screen once packaged.
2. Activate the plugin through the 'Plugins' screen in WordPress.
3. Go to the AlpineConsent menu item — assign a category to any discovered script you want held until consent.

== Changelog ==

= 0.6.37 =
* Legal pages tab: the per-language translation textareas now show plain, readable text (with light `## heading`/`**bold**`/`[link](url)` formatting) instead of raw HTML source — reported directly as unusable and risky to hand-edit.
* The auto-generated cookie/script table inside the Cookie Policy and Privacy Policy cookies section is no longer something to translate by hand: it's represented by a single placeholder you can leave in place, move, or remove, and it always expands into the current, live table at render time — even inside an otherwise-saved translation.

= 0.6.36 =
* Fixed a real bug where "Scan site now" could never actually save a newly-discovered raw/hardcoded script or cookie, no matter how many times it was run — a WordPress core mechanism was silently reverting each scan's own new discoveries back to what was already saved before the scan. Scripts and cookies discovered passively (as real visitors load your pages) were never affected.

= 0.6.35 =
* New, experimental "Block raw scripts too" setting (off by default) — holds a hardcoded `<script>` (one your theme or a page builder writes directly into the page, not one WordPress itself loads) until the visitor consents, once you've categorized it on the Scripts & Categories tab. Previously such a script could be discovered and categorized but never actually held.

= 0.6.34 =
* Cookie Policy page: scripts within each category now show in a real table (Script/Provider/Purpose) instead of a bare list of URLs with no context.
* Cookies tab and Cookie Policy page now also list cookies a detected script's own provider is publicly documented to use, even when this scan's Set-Cookie-header check finds nothing — most analytics/marketing cookies are set by client-side JavaScript, invisible to that check.

= 0.6.33 =
* Legal pages tab: self-service per-language translation for the Cookie Policy, Legal Notice and Privacy Policy cookies section, gated behind a liability-acceptance checkbox — AlpineConsent drafts English text only, translating and keeping it legally correct in every other language is your own responsibility.
* All 3 legal-content shortcodes now accept an optional `lang` attribute (e.g. `[alpineconsent_cookie_policy lang="de"]`) to force one fixed language regardless of the visitor's own detected language.

= 0.6.32 =
* "Button & banner text" (Banner tab) now shows one sub-tab per language instead of stacking every language's fields in one long scroll.

= 0.6.31 =
* Fixed the admin menu icon showing at its full original size instead of a normal small menu icon.

= 0.6.30 =
* Fixed the "Show with our default theme" preview checkbox on the Legal Notice and Cookie Policy panels (Legal pages tab) — checking it did nothing. The Privacy Policy cookies-section panel was never affected.

= 0.6.29 =
* The plugin's own admin settings screens (not the visitor-facing banner) can now follow your WordPress admin language — German, Italian, and Persian are included as a starting point (machine-assisted, not yet reviewed by a native speaker). Any other language, or any string not yet covered, shows in English as before.

= 0.6.28 =
* The "View details" popup (from your Plugins list) now shows a real Description, Installation, FAQ, and Changelog — pulled straight from this same readme — plus a proper banner image, instead of just a changelog snippet.

= 0.6.27 =
* The admin menu icon is now your site's real logo instead of an abstract monochrome silhouette.
* "Scan site now" now checks your homepage plus a few of your other pages and posts, instead of only the homepage.

= 0.6.26 =
* "Scan homepage now" now also discovers a script hardcoded directly into a page (for example, pasted into a page-builder module) instead of loaded the normal WordPress way — it's listed and can be categorized like any other script, though it can't yet be held until consent the way an ordinary script can (a separate improvement, tracked for later).

= 0.6.25 =
* Rotated the cryptographic key this plugin uses to verify update signatures, as a precaution. This has no visible effect — updates continue to be verified before installing, exactly as before.

= 0.6.24 =
* Polylang detection (used to pre-populate its known cookie on the Cookies tab) now checks the `POLYLANG_VERSION` constant Polylang always defines, instead of a function name — no behavior change for a real site, just a more robust detection primitive.

= 0.6.23 =
* One "Save changes" button instead of two — the settings screen used to show a second copy right under the tab nav, which looked redundant on a short tab. It's now a single button that stays visible at the bottom of your screen as you scroll, so it's never far away even on a long tab like Scripts & Categories.

= 0.6.22 =
* Removed the "Force a fixed language" override on the Banner tab — AlpineConsent never forces a language of its own; the banner's language always follows real detection (WPML/Polylang, or your site's own WordPress language).
* New "Button & banner text" section on the Banner tab: every button (Accept, Reject, Manage preferences, Save preferences), every category label, and the "Powered by AlpineConsent" badge text are now editable per language, for every language your site actually has — pre-filled with a suggested translation (German/Italian) or plain English as a starting point.
* If you're running a German or Italian site today: your button text keeps working exactly as before, but it now lives in these new editable fields instead of being hardcoded — visit the Banner tab and click "Save changes" once after updating, so your existing translation is carried over as a real, editable setting.

= 0.6.21 =
* Reorganized the admin screen: tabs are now Scripts & Categories, Banner, Cookies, **Legal pages** (new — the Cookie Policy, Legal Notice, and Privacy Policy cookies-section generators, previously scattered across other tabs, now live together), and Settings.
* The Banner tab now has its own Settings/Preview sub-tabs. The live preview loads your **real homepage** with the banner shown on top of your site's own actual look, instead of a plain blank page.
* The live preview's language switcher now shows exactly your own site's real languages (from WPML/Polylang, or just your default if none) — never a language your site doesn't actually have.
* The Cookie Policy / Legal Notice / Privacy Policy cookies-section previews each gained a "Show with our default theme" checkbox — off by default (these pages are intentionally unstyled, so they inherit your site's real theme), lets you preview roughly how it would look with none of your own styling applied.
* Fixed the AlpineConsent menu icon for real this time: WordPress recolors every menu icon's fill to white, so the earlier navy-background design became an invisible white-on-white square. It's now a single white silhouette, the same convention every other plugin's monochrome menu icon uses.
* The "Save changes" buttons no longer float loose on the page — each now sits inside its own card, matching the rest of the screen.

= 0.6.20 =
* Clarified the Banner tab's "Force a fixed language" setting (previously just "Language"). Reported live by a site running WPML with 2 languages: that dropdown only ever offers the (unrelated, small) list of languages this plugin has full built-in translations for, and was easy to mistake for a broken version of the site's own detected-language list shown just below it — the description text now explains this is a separate, independent setting, and mentions Italian (previously missing from the text even though it's a real option in the list). Superseded by 0.6.22 above, which removes this setting entirely.

= 0.6.19 =
* "Scan homepage now" now also recognizes the well-known cookies of a handful of active plugins (currently Polylang, WPML, WooCommerce) and lists them on the Cookies tab — most of these are set by JavaScript in the visitor's browser, not in the page response this scan reads, so they were invisible before.

= 0.6.18 =
* Fixed the AlpineConsent menu icon not showing in the WordPress admin sidebar on some sites (the icon SVG was missing explicit dimensions).
* Fixed the Cookie Policy / Legal Notice previews on the settings screen rendering as unreadable white-on-white text.
* Clearer message on the Cookies tab when a homepage scan finds no cookies in the response headers — this is normal (most tracking cookies are set later by JavaScript in the visitor's browser); the guidance now explains what to do instead of implying the scan failed.

= 0.6.17 =
* Plugin updates are now cryptographically signed and verified. Before an update is installed, the plugin downloads its package and a detached signature and checks the signature against a key built into the plugin; an unsigned, altered, or unverifiable package is refused rather than installed. This protects the update channel even if AlpineConsent's own release server were compromised — the signing key is held offline, never on that server. (This also switches the automatic update check to `releases.alpineconsent.com`, an AlpineConsent-owned indirection layer, so the release hosting can move in future without another plugin update.)

= 0.6.16 =
* New live banner preview on the Banner tab. The real consent banner renders right there in the settings screen and updates as you edit — layout, per-language title/description, buttons, custom links, logo — before you save anything. A "Preview language" switcher shows how each of your configured languages looks. The preview runs the exact same widget your visitors get, isolated in a frame so it never covers the settings page.

= 0.6.15 =
* New Legal Notice / Impressum generator. On the Settings tab: a live preview of an Impressum built from your company details (name, address, managing director, commercial register, VAT ID, phone, email — new fields on the same tab), with the § 5 DDG / § 5 ECG identification block, the EU online-dispute-resolution pointer, and the standard short liability clauses. Same behaviour as the Cookie Policy page — one-click "Create & publish" / "Create as a draft", or paste the `[alpineconsent_legal_notice]` shortcode into a page you already have. It never creates a page on its own.
* New "Privacy Policy — cookies section". AlpineConsent does not generate a whole Privacy Policy (it can't see your contact forms, shop, newsletter, hosting, or payment providers). This is only the cookies / tracking part — controller identity, the discovered-cookie table with legal basis, and your data-subject rights — as a `[alpineconsent_privacy_cookies_section]` shortcode to paste as one section into your own Privacy Policy. The Settings tab lists what the rest of your policy still has to cover.

= 0.6.14 =
* New Cookie Policy page generator. On the Cookies tab: a live preview of the page, and — if you don't have a policy page yet — a one-click "Create & publish" or "Create as a draft". It never creates a page on its own. The generated page contains just an `[alpineconsent_cookie_policy]` shortcode, so it stays current on every re-scan with nothing to regenerate; you can also drop that shortcode into a page you already have.
* The generated page is a full Cookie Policy, not just a table: it explains what cookies and similar technologies are, the consent/legal basis (GDPR and ePrivacy), a per-category description with the discovered cookies (provider, purpose, retention), a third-party-cookies note, how to control or delete cookies, and your GDPR rights — linking your site's own Privacy Policy page when one is set. The company name, address and email from Settings → AlpineConsent are used for a "Questions or complaints" contact section, and the page reads as your own document (no "generated by" attribution). It carries no styling of its own, so it inherits your theme's fonts and colours.

= 0.6.13 =
* The banner Description field now supports simple **bold** and [link text](https://example.com) formatting — plain text otherwise, no other HTML.
* New optional banner Logo: pick an image from your Media Library, or paste a direct URL. Shown above the title in every language; a broken image URL just removes itself instead of leaving a broken-image icon.

= 0.6.12 =
* Real per-language banner title/description: Settings -> AlpineConsent now shows one Title/Description field per language your site actually has active (detected from WPML, Polylang, TranslatePress, or Weglot — the page also tells you which one it found), pre-filled with your English text as a starting point to translate. Leave a language's field blank to use its own built-in default text instead.
* The bundled widget script (also used by the Universal Script Tag on non-WordPress sites) now auto-detects the visitor's browser language when nothing else says otherwise, instead of always defaulting to English.

= 0.6.11 =
* Added the "External services" and "Frequently Asked Questions" sections to this readme — real disclosure of the two things this plugin actually talks to AlpineConsent for (automatic update checks, and the optional Connect flow), ahead of a future WordPress.org Plugin Directory submission.

= 0.6.10 =
* Internal-only hotfix: the previous release's badge-removal fix pushed the widget's own script over its hard 5 KB size budget, caught by our own CI. No behavior change for site owners — the badge removal from 0.6.8 works exactly the same, just implemented a few bytes leaner.

= 0.6.8 =
* Fixed a real bug: the "Powered by AlpineConsent" badge on the consent banner rendered for every plan, including paid ones — despite Watermark Removal being an advertised Pro/Business/Enterprise feature. The badge is now actually removed once your site is connected to a paid AlpineConsent plan (Settings -> Connect to AlpineConsent).

= 0.6.7 =
* Fixed the new Settings tab's own section headings ("AlpineConsent account", "Behavior") rendering in a near-invisible dark color against the dark card background — found live, right after 0.6.6 shipped.
* Fixed a real testing gap in the Connect flow: connecting a local WordPress test site (e.g. wp-env/Local/Valet, all plain http) always failed with a confusing "returnUrl must be https" error, even though local testing was always meant to work — localhost/127.0.0.1 is now correctly exempted, and the error message for a real non-local, non-https site is now a clear, specific explanation instead of a bare technical string.

= 0.6.6 =
* New "Connect to AlpineConsent" button on a new Settings tab — links this site to your AlpineConsent account (sign in on alpineconsent.com, confirm, and you're brought straight back) so the plugin knows your real plan, without ever copy-pasting a key by hand. A site you never connect keeps working exactly as before, fully standalone.
* New Settings tab also adds two toggles — show/hide the banner and turn script-blocking on/off — plus company details (used for automatic legal-text generation in a future release).

= 0.6.5 =
* Fixed "Scan homepage now" only ever adding brand-new scripts/cookies to the Suggested column — an already-discovered script or cookie kept its very first suggestion forever, even after later plugin updates taught the classifier to recognize it correctly. Rescanning now refreshes the suggestion for already-known entries too, without ever touching a category you've already assigned yourself.

= 0.6.4 =
* Category suggestions synced against the public scanner's own classifier, closing a real gap between the two: recognizes jQuery and other WordPress-core-bundled libraries, WordPress core's own @wordpress/* packages, plugins that serve their tracker from /wp-content/uploads/ (Burst Statistics and others), must-use plugins (/wp-content/mu-plugins/ and VIP's /wp-content/client-mu-plugins/), and Cloudflare's own /cdn-cgi/ path (email obfuscation and similar built-in features, recognized on any Cloudflare-proxied site). Also adds around two dozen real hosts and several WordPress plugin slugs found scanning live sites this session (Osano, DataDome, NoBid, Optimizely, Sailthru, Complianz, and others). A handful of already-recognized plugins/themes (Divi, Elementor, Contact Form 7, and others) now get a real category suggestion instead of none at all.

= 0.6.3 =
* Fixed "Check Again" (Dashboard -> Updates) not actually re-checking for a new version — this plugin's own update cache wasn't being cleared alongside WordPress's own, so a manual check could still show stale results.
* Fixed the dropdown arrow rendering oversized and overlapping option text; the custom-links table now actually reserves the URL column its own width instead of squeezing it back down.
* Category suggestions now also recognize well-known plugins (WooCommerce and similar) from their /wp-content/plugins/ URL path, for scripts served from the site's own domain where the host alone gives no clue.

= 0.6.2 =
* Fixed the branded admin theme: buttons and dropdowns could become unreadable on hover/focus (text same color as background), the masthead now shows the real site logo, and the custom-links table is no longer capped to a fixed width.
* Category suggestions now also check the script's WordPress handle name (e.g. "csrf", "analytics", "pixel") when its source URL alone doesn't match a known provider.

= 0.6.1 =
* The settings page is now visually branded to match alpineconsent.com — navy background, Consent Green accent, card-based sections — instead of bare, unstyled Settings API chrome.

= 0.6.0 =
* Settings moved out from under Settings into their own top-level AlpineConsent menu item, reorganized into Banner / Scripts & Categories tabs, with a Save button at both top and bottom and "Scan homepage now" moved directly above the scripts table.
* Category labels updated to Functional (Essential) / Preferences / Statistics / Analytics / Marketing / Tracking; auto-suggestion matching extended to a few more well-known providers.
* The banner description now preserves line breaks instead of collapsing multi-line text to one line; the "Manage preferences" panel's Save button now sits directly with the checkboxes it saves.
* The plugin now checks for and can install updates the normal WordPress way (Plugins list "Update now"), without needing WordPress.org.

= 0.5.0 =
* Automatic banner language detection: follows WPML or Polylang's own per-visitor language when either is active, otherwise your site's WordPress language setting. A new "Language" dropdown under Settings -> AlpineConsent lets you fix it to German or English instead, overriding both.

= 0.4.0 =
* Banner customization: layout (modal, bar top/bottom, floating), title/description text, and a configurable button set (show/hide, reorder, button-or-link style) for Accept/Reject/Manage, plus custom link buttons (e.g. Privacy Policy, Cookie Policy, Imprint) with a one-click autofill from WordPress's own Privacy Policy page.
* The banner's language now follows the site's own WordPress language setting (German or English).
* A "Powered by AlpineConsent" badge is now shown on the banner (free plan).

= 0.3.0 =
* Automatic script discovery: every tracked script is found as visitors load your pages (or on demand via a "Scan homepage now" button), with a suggested category pre-filled for well-known trackers. Replaces the old manual-handle-entry textareas with a single table.

= 0.2.0 =
* Real prior-blocking: a `script_loader_tag` filter holds any script assigned a category (via the new Settings -> AlpineConsent page) until a visitor consents to that category.
* The loader now enqueues the real AlpineConsent widget (granular categories, blocking engine, Consent Mode v2) instead of a placeholder stub.

= 0.1.0 =
* Initial development skeleton: plugin bootstrap and stub loader enqueue.
