New cmp_mode setting toggles between the built-in banner (default, unchanged) and a bridge mode that defers banner UX to an external IAB TCF v2.2 certified CMP — e.g. Google's free Privacy & messaging (Funding Choices) or Tarteaucitron.js — and listens to __tcfapi to keep custom-script gating, attribution preservation, the att_cc_consent cookie cache and the WP Consent API bridge in sync. Lets sites that need a Google-certified CMP for EEA/UK AdSense/AdMob serving keep using this plugin for everything except the consent UI itself. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5.1 KiB
ATT Consent - Developer Context
What This Is
A WordPress plugin implementing Google Consent Mode v2 with session attribution preservation. It replaces paid CMv2 plugins (e.g., CookieYes) with a self-contained, distributable alternative.
Architecture
Core Flow
- Inline
<head>script (priority 1) - Sets consent defaults and captures attribution to sessionStorage. Must run before any Google tags. - Tracking script (priority 2) - Loads gtag.js or GTM. In Advanced mode, loads immediately. In Basic mode, deferred until consent.
- Footer - Banner HTML + enqueued
banner.jsandbanner.css.
CMP Mode
The cmp_mode setting toggles between two operating modes:
self(default) - this plugin renders the banner, owns the consent decision, and writes theatt_cc_consentcookie. Original behaviour.tcf_bridge- an external IAB TCF v2.2 certified CMP (e.g. Google's free Privacy & messaging / Funding Choices banner, Tarteaucitron.js) renders the banner and emits the official TC string +gtag('consent', ...)calls. The plugin suppresses its own banner/modal/consent default, and instead loadspublic/js/tcf-bridge.js, which listens to__tcfapi('addEventListener', 2, …), maps TCF purposes back to the three categories, and feedsAttConsent.update()so custom-script gating, attribution preservation and the WP Consent API bridge continue to work. Used when the site needs to satisfy Google's CMP requirement for EEA/UK/CH AdSense/AdMob traffic.
Key Files
includes/class-frontend.php- Orchestrates the output order. Theoutput_consent_defaults()method generates the critical inline script.public/js/consent-manager.js- Core logic:AttConsent.update()replays attribution, sends consent signals, injects scripts, sets cookie. This is the public API.public/js/banner.js- UI only. CallsAttConsent.update()on button clicks.includes/class-admin.php- Admin settings with 5 tabs. Handles save viaadmin_post, scripts CRUD via AJAX.includes/class-scripts-manager.php- CRUD for custom JS snippets stored in{prefix}att_cc_scriptstable.
Settings
Single serialized option: att_consent_settings. Access via ATT_Consent::get_settings() which merges with defaults.
Custom Scripts Table
{prefix}att_cc_scripts (id, name, snippet, category, placement, status, priority, created_at, updated_at)
Scripts are rendered in PHP as inert <script type="text/plain" data-att-cc-category="{category}"> tags (head scripts at priority 99, footer scripts at priority 99). Non-script HTML (pixels, iframes) is wrapped in <template data-att-cc-category="..." data-att-cc-type="html">. On consent, consent-manager.js scans the DOM for matching elements and activates them by creating fresh executable copies.
Third-party plugins (e.g. HFCM) can output consent-gated scripts without any coupling to this plugin — they just need to use type="text/plain" and the data-att-cc-category attribute with a valid category (functional, analytics, marketing).
Consent Cookie
Name: att_cc_consent. Value: JSON {"functional":bool,"analytics":bool,"marketing":bool}. First-party, SameSite=Lax.
Attribution Storage
sessionStorage key att_cc_attr stores referrer, UTMs, GCLID/DCLID on first page of session. Key att_cc_consent_given tracks whether attribution has been replayed. Attribution is replayed via gtag('set') BEFORE gtag('consent','update') so GA4 session_start gets correct source.
Category-to-Signal Mapping
| Category | Google Signals |
|---|---|
| Necessary | security_storage (always granted) |
| Functional | functionality_storage, personalization_storage |
| Analytics | analytics_storage |
| Marketing | ad_storage, ad_user_data, ad_personalization |
WordPress Hooks
Filters: att_consent_settings_save, att_consent_banner_html
Actions: att_consent_before_banner, att_consent_after_banner
JS Event: att_consent_update (CustomEvent with detail: {functional, analytics, marketing})
Coding Standards
- WordPress PHPCS (WordPress-Extra)
- All admin inputs sanitized:
sanitize_text_field,sanitize_hex_color,absint,wp_kses_post - Nonce verification on all forms and AJAX
- Capability check:
manage_optionsfor all admin operations - Script snippets stored raw (admin-only input, intentionally executable)
- Frontend JS is vanilla - no jQuery dependency
- Text domain:
att-consent
Testing
Activate plugin, enter a GA4 Measurement ID in General settings, visit frontend. Verify:
window.dataLayercontains consent default withwait_for_update- Clicking Accept All fires
gtag('consent','update')with all granted - Cookie
att_cc_consentis set - Return visit: no banner shown, consent applied from cookie
- Attribution test: visit with
?utm_source=test, navigate without consenting, consent on page 2, check GA4 DebugView for correct source
Environment
- WordPress 6.8.3, Astra child theme
- Local Sites development environment
- WooCommerce + LearnPress site
- Previously used CookieYes (
cookie-law-infoplugin)