=== 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.49
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, Polylang, WP Multilang, TranslatePress, or Weglot, 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 for 42 languages (all 24 official EU languages, the rest of the EEA, and major world languages), or plain English as a starting point for anything else. Right-to-left languages (Arabic, Hebrew, Persian, and others) render with a correctly mirrored layout, both in the banner itself and while editing their text.

Not yet implemented: automatic theme-matching with your site's own colors/fonts.

== 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) **Activate license** (only if you click "Activate license" 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, and it has nothing to do with your company/legal details (see below). 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.

4) **Consent decisions** (only once this site is Connected to an AlpineConsent account)
A visitor's own browser sends which categories they granted or denied to power your dashboard's Consent data chart — no cookies, page content, or anything else about that visitor. A site you never connect sends nothing here at all; the banner and script-blocking still run entirely in the visitor's own browser either way. Sent from the visitor's browser directly to:
`https://api.alpineconsent.com/consent`
See [AlpineConsent's Privacy Policy](https://alpineconsent.com/privacy).

5) **Provider logo icons** (shown on the Scripts & Categories tab, admin-only)
When a discovered script's provider is recognized, your own browser loads that provider's logo directly from:
`https://api.alpineconsent.com/logos/`
This is a plain image request, the same as any `<img>` tag on any web page — no data about your site is sent. Only your own browser, while you're viewing the Scripts & Categories tab, requests these images; nothing is fetched or sent on a visitor's behalf.

Company/legal details you enter under Settings (name, address, VAT ID, and similar) are stored locally on this site only, in your own WordPress database — never sent to AlpineConsent, regardless of whether you've activated a license. "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? =

Only once this site has an activated license, and only which categories a visitor granted or denied — never a cookie value, page content, or anything else about them. Script-blocking itself always runs entirely in the visitor's own browser regardless. See "External services" above for everything this plugin does talk to AlpineConsent for.

= 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 — activating a license (Settings -> License) is optional and only relevant if you're on a paid plan. It has no bearing on your company/legal details, which always stay local to this site.

= Is my company information ever stored on AlpineConsent's servers? =

No. Your company/legal details never leave this site — they're stored only in your own WordPress database and used only to generate this site's own Cookie Policy, Legal Notice, and Privacy Policy cookies section.

= 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 has an activated license on a paid plan.

= What is the "Consent setup score"? =

A plain completion score (0-100) shown at the top of the AlpineConsent menu, based only on this plugin's own settings: is the banner on, are your detected scripts/cookies categorized, is your company/legal info filled in, and have you published a Cookie Policy and Legal Notice page. **It is not a legal compliance score** — we only see this plugin's own configuration, not your whole site, and a perfect 100 is not a guarantee you meet the GDPR, TKG, or TDDDG. It's a checklist, not a certificate. It never looks at whether your license is activated — a free-plan site can score 100 just as easily as a paid one.

== 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.49 =
* The suggested-translation dictionary for banner text now covers 42 languages — all 24 official EU languages, the rest of the EEA (Norwegian, Icelandic), major regional languages with real EU business presence (Turkish, Russian, Ukrainian, Albanian, Serbian, Bosnian), and major world languages by speaker count (Persian, Arabic, Hebrew, Chinese, Hindi, Japanese, Korean, Indonesian, Vietnamese, Thai) — up from just English/German/Italian. Machine-assisted, like the existing entries — not yet reviewed by a native speaker for any language, including the ones that were already there; always worth checking the exact wording before relying on it for a real compliance-facing banner. This is only ever the starting pre-fill an admin sees the first time they open a language's row — fully editable and saved independently either way.
* Right-to-left languages (Arabic, Hebrew, Persian, and others) now render with a correctly mirrored layout — both the banner itself (button order, text alignment) and the Banner tab's own per-language editing fields (title, description, button text), which previously always rendered left-to-right regardless of the language being edited.

= 0.6.48 =
* Added a "Consent setup score" at the top of the AlpineConsent menu — a plain 0-100 completion score based only on this plugin's own settings (banner on, scripts/cookies categorized, company info filled in, Cookie Policy and Legal Notice pages published), with a checklist linking straight to whatever isn't finished yet. Deliberately not a legal compliance score, and doesn't factor in whether your license is activated — see the new FAQ entry above.

= 0.6.47 =
* Scripts & Categories: a provider with more than one script now actually collapses (click to expand) — it only ever showed a header with no way to hide the rows underneath before. A provider with just one script skips the header/click entirely and shows its own icon directly, and now sorts after the real (collapsible) groups instead of mixed in among them, alongside scripts with no recognized provider. Also tightened up the header row's own layout — it used to read as heavier and less consistent than the rest of the table.

= 0.6.46 =
* Breaking change, for the better: your company/legal details (name, address, VAT ID, and similar) are local-only again, exactly like before v0.6.40 — the brief period where they were shared live with your AlpineConsent account, once connected, is retired. That data has been deleted from AlpineConsent's servers. Also renamed "Connect to AlpineConsent" to "Activate license" and moved it to the bottom of the Settings tab, since it only ever activated your plan — it never had anything to do with your company details, and the earlier naming made that easy to assume otherwise.

= 0.6.45 =
* The Settings tab now has two separate sections — "Behavior" (Show banner, Run blocker, Block raw scripts too) and "Company & legal details" (the 7 fields used to generate your legal pages) — instead of one shared "Behavior" heading covering both. Purely a display change: everything still saves together on one "Save changes" click.

= 0.6.44 =
* The Scripts & Categories table now groups a provider's scripts together with a real logo and a count, instead of one identical-looking row per script — a real scan turned up a page-builder add-on alone accounting for 5 rows. Each script still keeps its own independent category — the grouping is purely visual. The generated Cookie Policy does the same for a provider with more than one script in the same category, collapsing them behind a "Show N scripts" toggle.

= 0.6.43 =
* Visual polish: the AlpineConsent settings pages used seven different corner-rounding values across buttons, cards, tables, and form fields, added ad hoc as each was built over time. Consolidated to one consistent, intentional scale — no functional change.

= 0.6.42 =
* Added WP Multilang support: the banner's language now also follows WP Multilang's own per-visitor detection (alongside the existing WPML, Polylang, TranslatePress, and Weglot support), and Settings -> AlpineConsent's per-language rows pick up every language WP Multilang has enabled.

= 0.6.41 =
* Your dashboard's Consent data chart can now actually show real data for this site: once connected to your AlpineConsent account, a visitor's own browser reports which categories they granted or denied (never a cookie value or anything else about them). A site you never connect sends nothing here, exactly as before — the consent banner and script-blocking always run entirely in the visitor's own browser regardless.

= 0.6.40 =
* Once connected to your AlpineConsent account (Settings → Connect to AlpineConsent), your company/legal details (name, address, email, phone, managing director, commercial register, VAT ID) are now shared live with your account — the same details shown on your dashboard's Sites → Legal pages panel. Edit them from either place; there is nothing to keep in sync, since there's now only one real copy. A site you never connect keeps working exactly as before, fully local.

= 0.6.39 =
* Fixed a real bug: Scripts & Categories could pick up scripts that only ever load in your own wp-admin (Dashboard, Plugins, Site Health, and similar) while you're logged in managing the site — never something a real visitor sees. Beyond cluttering the table, this closed a narrow but real risk: if one of those admin-only scripts ever got assigned a blockable category, it could get silently disabled inside wp-admin itself, with no consent banner there to ever turn it back on.

= 0.6.38 =
* Fixed a real, long-standing bug: the vendored cookie database that powers the Cookies tab's Provider/Description matches and the "Known cookies for detected providers" section never actually shipped in the release zip. Every site that went through a real automatic update since this plugin's very first release lost this data silently (WordPress replaces the whole plugin folder on update) — those two features kept working right up until a site's first auto-update, then went quietly empty from then on with no visible error.

= 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.
