=== Consentl – Cookie Banner for GDPR & US Privacy Laws ===
Contributors: stlembededcreations
Tags: cookie consent, gdpr, cookie banner, consent mode, woocommerce
Requires at least: 6.5
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.1.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Cookie banner with region rules, consent log, WP Consent API and WooCommerce support. Consent Mode v2 and automatic blocking on paid plans.

== Description ==

Consentl connects your WordPress or WooCommerce site to the Consentl consent service. One script, placed first in `<head>`, shows the banner that matches the rules you set for each region and holds back the scripts you mark until the visitor agrees (automatic blocking of known trackers on the Business plan).

**What you get on every plan, including Free**

* **Region rules.** Ready-made rules for the EU, EEA, UK and Switzerland (opt-in), California and the other US states with privacy laws (opt-out, with Global Privacy Control honoured) and many more countries, on every plan. The banner follows the rule for the visitor's region: the Consentl service determines the visitor's country from the IP address, without storing it (US states are not told apart, so US visitors get your US rule). Visitors whose country cannot be determined get your rule for unknown regions (opt-in by default).
* **Holding back scripts you mark.** Tag your own scripts with `type="text/plain" data-consentl="analytics"` (or `preferences`, `marketing`) and they only run after consent.
* **WP Consent API.** Plugins that follow the [WP Consent API](https://wordpress.org/plugins/wp-consent-api/), such as Site Kit by Google, WooCommerce, WP Statistics and Burst Statistics, get the visitor's choice automatically.
* **WooCommerce.** Order attribution (sourcebuster.js) only runs after marketing consent. This works with full-page caching.
* **Cookie declaration.** A block or shortcode lists your cookies by category and stays in sync with your latest cookie scan (automatic monthly scans on the Business plan).
* **Privacy request form.** Visitors can ask to access, copy, correct or delete their data, or opt out of sale or sharing. Consentl verifies the e-mail address before the request reaches you.
* **"Cookie settings" link** so visitors can change or withdraw consent at any time. If a browser extension blocks the cookie settings, the link opens a short notice instead, where visitors can still reject all optional cookies and find your privacy policy.
* **Consent log.** Pseudonymous proof of consent, which you can export from the dashboard.
* **Accessible and multilingual.** The banner is designed to meet WCAG 2.2 AA; if you change its colours, check the contrast yourself. Banner texts come in more than 30 languages and follow WPML, Polylang or the site language. This plugin's admin screens are translated into all 24 official EU languages.
* **Small.** The script is printed inline at the top of the page (about 10 KB gzip including your settings), with no framework and no jQuery. The rest of the interface loads only when it is needed.

**On paid plans**

* **Google Consent Mode v2 and vendor signals** (Pro and higher). Regional defaults are sent before any Google tag runs, and updates follow every choice. Microsoft UET, Microsoft Clarity, Meta Pixel and TikTok consent APIs are also supported.
* **EU withdrawal form** (Pro and higher). An online withdrawal function for distance contracts with consumers, with a confirmation step and an acknowledgement e-mail. Since 19 June 2026, traders selling online to consumers in the EU must offer one (Directive (EU) 2023/2673); you can also provide it by other means.
* **Automatic blocking** (Business and higher). Known analytics and advertising scripts, iframes and pixels are held back until the visitor consents, without tagging them yourself. Before the page leaves your server, the plugin rewrites known tracker tags written in the page (`<script async src>`, `<img src>` pixels, `<iframe src>` embeds) into Consentl's blocking markup, so the browser cannot fetch them early. Images whose tracker is only in `srcset` are held back too, and resource hints to trackers (`<link rel="preload">`, `modulepreload`, `prefetch`, `preconnect`, `dns-prefetch`) are switched off, because the browser would otherwise contact the tracker before consent; a hint is only a speed-up, so it is not restored after consent (the tracker itself still loads). Synchronous `<script src>` tracker tags are not rewritten (their order matters): mark those by hand with `type="text/plain" data-consentl="…"`.
* **Automatic monthly cookie scans** (Business and higher).

Settings → Consentl shows your plan and which of these features are active on your site.

**How it works**

The banner, its texts, the regions, the cookie scanner and the consent log are run by the Consentl service and managed in the Consentl dashboard. This plugin stores your site key and prints the Consentl script as the first element of `<head>`. It passes each decision to the WP Consent API and WooCommerce, and it provides blocks and shortcodes for the forms. It has no consent logic of its own: every decision is made by the same script on every page.

The Free plan includes the banner, region rules, the consent log, the cookie scanner and declaration, and the privacy request form. Pro adds Google Consent Mode v2, vendor signals, the EU withdrawal form and editing the texts in every language. Business adds automatic blocking, monthly scans, age confirmation and more. See the Consentl website for current plans and prices.

**Blocks and shortcodes**

* `[consentl_cookie_declaration heading="Cookies we use"]` or the **Cookie declaration** block
* `[consentl_privacy_request]` or the **Privacy request form** block
* `[consentl_withdrawal_form]` or the **EU withdrawal form** block (Pro and higher; editors see a note when the plan does not include it)
* `[consentl_cookie_settings label="Cookie settings"]` or the **Cookie settings link** block. In menus, add a custom link to `#consentl`.

**For developers**

* `consentl_has_consent( 'analytics' )` is true when the visitor allowed the category (necessary, preferences, analytics, marketing or sale). It reads the `consentl` cookie, so you can gate tags rendered on the server. It applies the runtime's rules: a decision for an older version of your settings or past its lifetime does not count; an "implied" decision (OK on a notice or opt-out banner) is not consent, because the server does not know the visitor's region; and with a Global Privacy Control signal (`Sec-GPC: 1`) marketing and sale are false whenever one of your region rules honours GPC.
* `consentl_get_consent()` returns the stored decision while it is valid, or null.
* `consentl_loader_tag()` prints the script yourself, for themes that output scripts before `wp_head()`.
* JavaScript: `Consentl.get()`, `Consentl.allowed('marketing')`, `Consentl.on('change', fn)`, `Consentl.open('prefs')`, and the `consentl:change` event on `document`.
* Filters: `consentl_should_load`, `consentl_inline_loader`, `consentl_tracker_markup`, `consentl_purge_page_cache`, `consentl_loader_attributes`, `consentl_head_priority`, `consentl_locale`, `consentl_has_consent`, `consentl_woocommerce_attribution_client_side`, `consentl_api_origin`, `consentl_app_origin`, `consentl_self_update`.
* Action: `consentl_loader_changed( $site_key, $languages )` fires when your published settings changed, after the plugin purged the page caches it knows. Purge your CDN or reverse proxy here.

== External services ==

This plugin is a connector for the **Consentl** consent management service operated by STL Embeded Creations. It cannot work without that service. It only connects to the Consentl API origin (`https://api.consentl.com`), the Consentl dashboard (`https://app.consentl.com`) and, for plugin updates, the Consentl website (`https://consentl.com`).

* **From your server**, the plugin downloads `https://api.consentl.com/v1/loader.js` with your public site key and the page language and prints it in your pages. A scheduled task (WP-Cron) checks it every five minutes for each language your visitors used in the last week; when nothing changed the answer is a short "not modified". No visitor data is sent with this request.
* **On front-end pages**, the visitor's browser runs that script. Once per visit it asks the Consentl service (`/api/geo`) for the visitor's country, so that the right region rule applies; the service determines the country from the IP address of that request (DB-IP Lite database, in memory) and does not store or log the address for this. If the country cannot be determined, your rule for unknown regions applies. The region found is kept for the visit in the browser's session storage (`consentl_r`). When the banner is first shown, the browser sends an anonymous view count. When the visitor makes a choice, it sends a pseudonymous consent record to the service as proof of consent: a random ID (also kept in the cookie), the date and time, the banner version, the choices, the region and language, your site's host name and the page path (without query string), the IP address shortened to its network part (IPv4 /24, IPv6 /48), the browser's user-agent string and whether the browser sent a Global Privacy Control signal. The choice itself is stored in a first-party, strictly necessary cookie named `consentl`.
* **Consent records** are kept by Consentl, as your processor, as proof of consent for at least the lifetime of the choice plus 30 days: 425 days on Free and Pro, 730 days on Business and 1,825 days on Enterprise. Then they are deleted.
* **On pages with a Consentl block or shortcode**, the browser loads `https://api.consentl.com/v1/blocks.js`. The cookie declaration is fetched from `/api/cookies`. Privacy request and withdrawal forms send what the visitor enters (e-mail address, name, message, order number) to `/v1/requests` or `/v1/withdrawals`, so that Consentl can verify it and forward it to you.
* **In the admin area**, the Consentl settings screen asks `https://api.consentl.com/v1/status` whether your site key is valid, which plan it is on and whether your site's host name is allowed (every 10 minutes, or every minute while the key cannot be confirmed; it sends your site key, host name, the platform and the plugin version, and no visitor data). The "Connect to Consentl" button opens `https://app.consentl.com/connect` with your site's domain and the address of your settings page, so you can sign in and send the site key back.
* **Plugin updates.** The plugin is downloaded from consentl.com, so it asks consentl.com for new versions: whenever WordPress checks for plugin updates (about twice a day, at most once every 12 hours, and when you click "Check again" under Dashboard → Updates), your server downloads `https://consentl.com/downloads/wordpress/update.json`, and when you update the plugin it downloads the new zip file from consentl.com. The request sends no site key, site address or visitor data, only the plugin version in the user agent. Switch it off with `define( 'CONSENTL_SELF_UPDATE', false );` in `wp-config.php` (you then install new versions yourself).

The plugin itself collects no data and contains no tracking or analytics.

* Terms of service: https://consentl.com/legal/terms
* Privacy policy: https://consentl.com/legal/privacy

== Installation ==

1. Install and activate **Consentl** from Plugins → Add New, or upload the zip file.
2. Go to **Settings → Consentl** and click **Connect to Consentl**. Sign in or create a free account, then pick or create the site. You are sent back with your site key filled in. You can also paste the key (it starts with `sk_`) from the dashboard.
3. Optional: install the [WP Consent API](https://wordpress.org/plugins/wp-consent-api/) plugin so other plugins follow the visitor's choice.
4. Add the cookie declaration, privacy request form and a "Cookie settings" link to your privacy or cookie policy page.
5. If you use a page cache, clear it once (later changes to your Consentl settings purge the common page caches automatically).

To pin the key per environment, add `define( 'CONSENTL_SITE_KEY', 'sk_…' );` to `wp-config.php`.

== Frequently Asked Questions ==

= Do I need an account? =

Yes. The banner, texts, cookie scanner and consent log are provided by the Consentl service. A free plan is available.

= Which features does the Free plan include? =

The banner with region rules for every supported law, the consent log, the cookie scanner and declaration, the privacy request form, the WP Consent API and WooCommerce integration, and holding back the scripts you tag yourself. Google Consent Mode v2, vendor signals and the EU withdrawal form need the Pro plan; automatic blocking of known trackers and monthly scans need the Business plan. Settings → Consentl shows what is active on your site.

= Where do I change the banner design, texts or regions? =

In the Consentl dashboard. Use the "Open the Consentl dashboard" button in Settings → Consentl. Your site picks up a change within about five minutes (the next run of the plugin's scheduled task; "Check again" in Settings → Consentl fetches it at once). See the next question for page caches.

= Does it work with caching and optimisation plugins? =

Yes. The page HTML is the same for every visitor, and each visitor's choice is applied in the browser. The script is printed inline and automatically excluded from deferring, delaying and combining in WP Rocket, LiteSpeed Cache, Autoptimize, SiteGround Speed Optimizer, Jetpack Boost and Cloudflare Rocket Loader. For other optimisation plugins, exclude scripts containing `window.consentl` and `/v1/loader.js`. Server-side checks with `consentl_has_consent()` read the visitor's cookie, so do not cache those parts per page.

Your Consentl settings travel inside every page, so a cached page keeps the settings it was cached with. When your settings change, the plugin purges the page cache of WP Super Cache, W3 Total Cache, WP Rocket, LiteSpeed Cache, WP Fastest Cache, SiteGround Speed Optimizer and the Cloudflare plugin (including APO) for you. Pages kept by a cache outside WordPress (a CDN or reverse proxy without a WordPress plugin, Varnish, your host's cache) keep the old settings until they expire there: purge that cache yourself after changing your Consentl settings, or purge it from the `consentl_loader_changed` action. Until then, a visitor who moves between an old cached page and a fresh page after you asked everyone to choose again ("reset consents") can be asked more than once.

The scheduled task needs WP-Cron. If you switched WP-Cron off (`DISABLE_WP_CRON`), run `wp-cron.php` from a system cron every five minutes; otherwise the plugin refreshes the script during a page view once it is 15 minutes old.

= My site has a strict Content Security Policy. =

The script is printed inline through `wp_print_inline_script_tag()`, so CSP nonce plugins work. Without a nonce plugin, add `add_filter( 'consentl_inline_loader', '__return_false' );` to load it from `https://api.consentl.com` instead, and allow that origin in `script-src` and `connect-src`.

= Is the script really the first thing in <head>? =

The plugin prints it at the earliest `wp_head` priority, before every enqueued script. Some themes or plugins print scripts before `wp_head()`, for example a Google Tag Manager snippet pasted straight after `<head>`. In that case, call `consentl_loader_tag()` before them, or move those snippets into `wp_head`.

= Does it support Google Consent Mode v2? =

Yes, on the Pro plan and higher, when Consent Mode is switched on in the dashboard. Defaults for each region are set before Google tags load, and updates are sent on every choice. Google tags and GTM tags with built-in consent checks work without extra setup. GTM also receives a `consentl_consent` dataLayer event.

= How does it work with WooCommerce? =

WooCommerce's order attribution only starts after marketing consent, and its cookies are removed when consent is withdrawn. Checkout, cart and session cookies are strictly necessary and are not affected. Order attribution data is only filled in for visitors who agreed.

= Which WP Consent API categories are used? =

Necessary maps to functional (always allowed), preferences to preferences, analytics to statistics and statistics-anonymous, and marketing to marketing. The consent type follows the rule for the visitor's region: optin in opt-in regions (and when the region is unknown, by default), optout elsewhere.

= Is it compatible with WPML and Polylang? =

Yes. By default the banner follows the language of the current page. You can also force the site language or a fixed language.

= Does it support multisite? =

Yes. Each site in the network has its own settings and site key. In a subdirectory network (`example.com/` and `example.com/shop/`) all sites share one host name and therefore one `consentl` cookie, so a visitor's decision on one site also counts on the others: use the same site key for all sites on that host name. Subdomain networks and separate domains are not affected.

= My admin area runs on a different host than my site. =

When you connect, Consentl asks you to confirm both host names. If the dashboard says the connection link is invalid, copy the site key from the dashboard (Sites → Install) and paste it in Settings → Consentl.

= What do visitors see when an ad blocker blocks the banner? =

Some ad blockers block the banner's interface while the rest of Consentl keeps running, so nothing is allowed without consent. The "Cookie settings" link and block then open a short notice: the cookie settings could not be loaded, with a "Reject optional cookies" button and a link to your privacy policy page (Settings → Privacy). Visitors can still withdraw their consent this way. Developers can point the link elsewhere with the `consentl_policy_link` filter, or switch the notice off with `consentl_ui_fallback`.

= How do I get updates? =

Like any other plugin: WordPress shows a new version under Dashboard → Updates and on the Plugins screen, and you can update with one click or switch on auto-updates. Until the plugin is published on WordPress.org, the versions come from consentl.com (see "External services"). If your server blocks external requests (`WP_HTTP_BLOCK_EXTERNAL`), add `consentl.com` to `WP_ACCESSIBLE_HOSTS` (next to `api.wordpress.org`, which WordPress needs for every update check), or download the new zip from consentl.com and upload it under Plugins → Add New → Upload.

= What happens when I uninstall the plugin? =

The plugin's settings and cached data are deleted. Your consent log stays in your Consentl account, because it is your proof of consent.

== Screenshots ==

1. Settings → Consentl: connection status, plan, site key, banner language and integrations.
2. The cookie banner on the front end (opt-in region).
3. The preferences dialog with categories.
4. The Cookie declaration block in the block editor.
5. The privacy request form on a privacy policy page.
6. The Consentl dashboard: banner design and regions.

== Changelog ==

= 1.1.0 =
* Updates from consentl.com: WordPress now shows new versions of the plugin under Dashboard → Updates and on the Plugins screen, with "View details", one-click updates and auto-updates, also in a multisite network admin. The update information is cached for 12 hours (one hour after a failed check), and the check never slows down your admin when consentl.com cannot be reached. Switch it off with the `CONSENTL_SELF_UPDATE` constant.

= 1.0.0 =
* First release: connect flow, loader printed inline first in `<head>` (with the external script as fallback), WP Consent API bridge, WooCommerce order attribution gating, cookie declaration, privacy request and EU withdrawal blocks and shortcodes, "Cookie settings" link, server-side `consentl_has_consent()`, plan and feature overview, translations for the 24 official EU languages.

== Upgrade Notice ==

= 1.1.0 =
WordPress now finds new versions of Consentl on consentl.com, so later updates appear under Dashboard → Updates.

= 1.0.0 =
First release.
