Files
att-consent/CLAUDE.md
Steve Hanlon 0a73181ea7 Refactor script injection to type="text/plain" inert pattern
Custom scripts are now rendered as inert <script type="text/plain"
data-att-cc-category="..."> tags in the page HTML. On consent,
consent-manager.js scans the DOM and activates matching elements.
This replaces the JSON-in-config approach and allows third-party
plugins (e.g. HFCM) to output consent-gated scripts using the
same data attribute convention.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 09:28:11 +00:00

4.2 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

  1. Inline <head> script (priority 1) - Sets consent defaults and captures attribution to sessionStorage. Must run before any Google tags.
  2. Tracking script (priority 2) - Loads gtag.js or GTM. In Advanced mode, loads immediately. In Basic mode, deferred until consent.
  3. Footer - Banner HTML + enqueued banner.js and banner.css.

Key Files

  • includes/class-frontend.php - Orchestrates the output order. The output_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. Calls AttConsent.update() on button clicks.
  • includes/class-admin.php - Admin settings with 5 tabs. Handles save via admin_post, scripts CRUD via AJAX.
  • includes/class-scripts-manager.php - CRUD for custom JS snippets stored in {prefix}att_cc_scripts table.

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

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_options for 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.dataLayer contains consent default with wait_for_update
  • Clicking Accept All fires gtag('consent','update') with all granted
  • Cookie att_cc_consent is 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-info plugin)