1(function () { 2"use strict"; 3 4var data = window._fazGcm; 5if (!data) { 6 return; 7} 8var setDefaultSetting = true; 9var regionSettings = Array.isArray(data.default_settings) ? data.default_settings : []; 10var waitForTime = data.wait_for_update || 0; 11 12function getCookieValues(cookieName) { 13 var values = []; 14 var name = cookieName + "="; 15 var parts = document.cookie.split(';'); 16 17 for (var i = 0; i < parts.length; i++) { 18 var cookie = parts[i]; 19 while (cookie.charAt(0) === ' ') { 20 cookie = cookie.substring(1); 21 } 22 if (cookie.indexOf(name) === 0) { 23 var raw = cookie.substring(name.length, cookie.length); 24 try { 25 values.push(decodeURIComponent(raw)); 26 } catch (e) { 27 values.push(raw); 28 } 29 } 30 } 31 return values; 32} 33 34function getConsentStateForCategory(categoryConsent) { 35 return categoryConsent === "yes" ? "granted" : "denied"; 36} 37 38var dataLayerName = 39 data.data_layer_name || 40 (window.fazSettings && window.fazSettings.dataLayerName) || 41 "dataLayer"; 42window[dataLayerName] = window[dataLayerName] || []; 43function gtag() { 44 window[dataLayerName].push(arguments); 45} 46 47function setConsentInitStates(consentData) { 48 // Advanced Consent Mode (#165): the synchronous denied `consent default` 49 // is already emitted inline in <head> (print_gcm_default_inline) so it 50 // runs before the page's gtag snippet. Skip here so we never emit a 51 // SECOND `consent default`, which Consent Mode tooling flags as resetting 52 // consent (issue #149). The `consent update` path is unchanged. 53 if (data.advanced_mode) return; 54 if (waitForTime > 0) consentData.wait_for_update = waitForTime; 55 gtag("consent", "default", consentData); 56} 57 58// Non-personalized-ads fallback signal for LEGACY (non-Consent-Mode) ad tags, 59// which don't read ad_storage. When the publisher enabled the fallback, mirror 60// the ad_storage decision into `npa`: 1 (non-personalized) while ad_storage is 61// denied, 0 once granted. Two-sided + called from every path (first-visit 62// default, region rows, and the post-action update) so the signal is consistent 63// and self-clears within the session â Consent Mode v2 tags already read 64// ad_storage directly. 65function setNpaIfDenied(adStorage) { 66 if (!data || !data.non_personalized_ads_fallback) return; 67 gtag("set", { npa: adStorage === "denied" ? 1 : 0 }); 68} 69 70// In Advanced Consent Mode these are already emitted by the synchronous 71// inline <head> bootstrap (print_gcm_default_inline); skip here to avoid a 72// duplicate set (#165 F6). Both paths use the same dataLayer array (F4), so 73// the skip is purely cosmetic, but keeping a single emitter is cleaner. 74if (!data.advanced_mode) { 75 gtag("set", "ads_data_redaction", !!data.ads_data_redaction); 76 gtag("set", "url_passthrough", !!data.url_passthrough); 77} 78 79// IMPORTANT: we must parse the consent cookie BEFORE emitting any consent 80// states. We follow the standard Consent Mode pattern (matching CookieYes 81// upstream): a single baseline `consent default` (region-specific / denied, 82// carrying wait_for_update), then â for a returning visitor with a stored 83// cookie â a `consent update` carrying their granted states. wait_for_update 84// holds ad tags (AdSense, GTM) until the update lands, so there is no 85// denied-ad race. Emitting a SECOND `consent default` with granted values 86// instead is flagged by Consent Mode tooling as resetting consent (issue #149). 87// 88// Order matters: 89// 1. parseConsentCookie() -> read cookie synchronously 90// 2. emit the region-specific / denied baseline `consent default` 91// (Basic mode). In Advanced Consent Mode (#165) this step is SKIPPED 92// here â setConsentInitStates() early-returns â because the denied 93// baseline is already emitted synchronously in <head> by 94// print_gcm_default_inline(), as a single GLOBAL most-restrictive 95// default rather than per-region. 96// 3. if cookie present -> emit `consent update` with the stored grants 97// 98// FAZ_META_KEYS must be declared BEFORE this call: parseConsentCookie() reads 99// it, and although the function is hoisted, the `var` only hoists the 100// declaration (not the value). Declaring it lower in the file left it 101// `undefined` at this call site, so a returning visitor (or a PMP-exempt member 102// with an auto-granted cookie) hit "Cannot read properties of undefined" on the 103// first key and gcm.js threw before emitting any consent. 104// Non-category meta keys stored in the consent cookie (not consent states). 105// `gpc` flags a consent recorded automatically from a Global Privacy Control 106// signal; like rev/action/consentid it must not be coerced to granted/denied. 107var FAZ_META_KEYS = { rev: 1, action: 1, consentid: 1, gpc: 1 }; 108 109var initialCookieObj = parseConsentCookie(); 110 111// Baseline consent DEFAULT (region-specific / denied) is emitted first in 112// Basic mode â for first-time AND returning visitors. (In Advanced Consent 113// Mode it is emitted synchronously in <head> instead; setConsentInitStates() 114// below no-ops.) Consent Mode expects exactly one 115// well-formed `consent default` before any update; emitting a SECOND 116// `consent default` with granted values to restore a returning visitor (issue 117// #149) is flagged by Consent Mode tooling as resetting consent. The returning 118// visitor's stored grants are restored via `consent update` below instead â the 119// brief denied window is covered by wait_for_update on this baseline default. 120{ 121 // Region-specific defaults as configured by the admin. 122 // 123 // ad_storage stays at the admin-configured (typically "denied") regi
123on 124 // value before the visitor interacts. The "non-personalized ads fallback" 125 // does NOT grant ad_storage (that would write ad cookies without consent â 126 // unlawful under ePrivacy/Consent Mode v2 in EEA/UK/CH). Under Consent Mode 127 // v2 a denied ad_storage already lets Google serve non-personalized, 128 // cookieless ads; for legacy (non-Consent-Mode) ad tags we additionally 129 // signal `npa`. Unlike the Consent Mode `ad_storage` states above, `npa` is 130 // a GLOBAL gtag('set') value â it CANNOT be region-scoped â so emitting it 131 // per region row would let the last-iterated row win for everyone. Instead 132 // we track the most-restrictive ad stance across all applicable defaults and 133 // emit `npa` ONCE after the loop: npa:1 if ANY default denies ads. This 134 // protects denied regions from personalized legacy ads pre-consent without 135 // geofencing. buildConsentState() (update path) re-evaluates `npa` two-sided 136 // from the returning visitor's real choice. 137 var anyAdDenied = false; 138 for (var index = 0; index < regionSettings.length; index++) { 139 var regionSetting = regionSettings[index]; 140 if (!regionSetting || typeof regionSetting !== "object") continue; 141 // Read the category-mirror keys: these are the source of truth for the 142 // storage-type signals. The non-personalized-ads fallback deliberately 143 // keeps the `marketing` mirror and the canonical `ad_storage` OUT of sync 144 // (marketing drives ad serving here), so reading the mirrors is 145 // load-bearing â do NOT switch this to canonical-first. The runtime 146 // geo-routing override writes these same mirror keys (see 147 // Geo_Runtime::apply_cmv2_to_gcm) so its CMv2 signals reach gtag too. 148 var consentRegionData = { 149 ad_storage: regionSetting.marketing || regionSetting.advertisement || "denied", 150 analytics_storage: regionSetting.analytics, 151 functionality_storage: regionSetting.functional, 152 personalization_storage: regionSetting.functional, 153 security_storage: regionSetting.necessary, 154 ad_user_data: regionSetting.ad_user_data, 155 ad_personalization: regionSetting.ad_personalization 156 }; 157 var regionsRaw = typeof regionSetting.regions === "string" ? regionSetting.regions : ""; 158 var regionsToSetFor = regionsRaw 159 .split(",") 160 .map(function (region) { return region.trim(); }) 161 .filter(function (region) { return region; }); 162 if (regionsToSetFor.length > 0 && regionsToSetFor[0].toLowerCase() !== "all") 163 consentRegionData.region = regionsToSetFor; 164 else setDefaultSetting = false; 165 setConsentInitStates(consentRegionData); 166 if (consentRegionData.ad_storage === "denied") anyAdDenied = true; 167 } 168 169 if (setDefaultSetting) { 170 setConsentInitStates({ 171 ad_storage: "denied", 172 analytics_storage: "denied", 173 functionality_storage: "denied", 174 personalization_storage: "denied", 175 security_storage: "granted", 176 ad_user_data: "denied", 177 ad_personalization: "denied" 178 }); 179 anyAdDenied = true; 180 } 181 182 // Single global npa for the pre-consent default stage (see comment above): 183 // most-restrictive wins, since gtag('set', { npa }) is not region-scoped. 184 setNpaIfDenied(anyAdDenied ? "denied" : "granted"); 185} 186 187// Returning visitor with saved consent: restore it via `consent update` (the 188// GCM-correct restoration signal), NOT a second `consent default`. 189// buildConsentState() also emits the non-personalized-ads npa signal (two-sided) 190// so it self-clears here when marketing was granted. 191if (initialCookieObj) { 192 updateConsentState(buildConsentState(initialCookieObj)); 193} 194 195function parseConsentCookieParts() { 196 var raw = getCookieValues("fazcookie-consent")[0]; 197 if (!raw || typeof raw !== "string") return null; 198 return raw.split(",").reduce(function (acc, curr) { 199 var trimmed = curr.trim(); 200 // Match PHP's faz_parse_consent_cookie() which uses 201 // explode(':', $pair, 2) â split on the FIRST colon, not the last, 202 // so values containing colons (e.g. a future "source:pmp:L2" token) 203 // round-trip consistently between server and client. 204 var sepIdx = trimmed.indexOf(":"); 205 if (sepIdx === -1) return acc; 206 var key = trimmed.substring(0, sepIdx).trim(); 207 if (!key) return acc; 208 acc[key] = trimmed.substring(sepIdx + 1).trim(); 209 return acc; 210 }, {}); 211} 212 213function isConsentCookieStale(parsed) { 214 if (!parsed) return false;
215 var config = window._fazConfig || {}; 216 // wp_localize_script often stringifies numeric values ("1" instead of 1), 217 // so we can't rely on typeof === "number". Coerce and fall back to 1. 218 var serverRevisionRaw = config && config._consentRevision; 219 var serverRevision = parseInt(serverRevisionRaw, 10); 220 if (isNaN(serverRevision) || serverRevision < 1) serverRevision = 1; 221 var storedRevision = parseInt(parsed.rev, 10); 222 return serverRevision > 1 && (isNaN(storedRevision) || storedRevision < serverRevision); 223} 224 225function parseConsentCookie() { 226 var parsed = parseConsentCookieParts(); 227 if (!parsed || isConsentCookieStale(parsed)) return null; 228 Object.keys(parsed).forEach(function(key) { 229 // Leave meta keys (rev/action/consentid) as their raw value; only 230 // category slugs are coerced to granted/denied. 231 if (!FAZ_META_KEYS[key]) parsed[key] = getConsentStateForCategory(parsed[key]); 232 }); 233 // Backward compat: accept old "advertisement" key as alias for "marketing". 234 if (!parsed.marketing && parsed.advertisement) { 235 parsed.marketing = parsed.advertisement; 236 } 237 // Require only `necessary` â the one category guaranteed on every install. 238 // Other categories (analytics, marketing, functional, performance, or any 239 // custom slug) are optional; absent ones default to "denied" downstream in 240 // buildConsentState(). Hard-requiring a fixed slug list rejected the cookie 241 // on installs that renamed/replaced a default category (e.g. "performance"). 242 if (parsed.necessary !== "granted" && parsed.necessary !== "denied") { 243 return null; 244 } 245 return parsed; 246} 247 248// Read a category's consent state, defaulting absent categories to "denied". 249function fazCat(cookieObj, slug) { 250 return cookieObj && cookieObj[slug] === "granted" ? "granted" : "denied"; 251} 252 253function buildConsentState(cookieObj) { 254 var marketing = fazCat(cookieObj, "marketing"); 255 // analytics_storage is granted when EITHER the "analytics" OR the 256 // "performance" category is granted (performance is a valid analytics-class 257 // slug on some installs); previously "performance" was dropped entirely. 258 var analytics = 259 fazCat(cookieObj, "analytics") === "granted" || fazCat(cookieObj, "performance") === "granted" 260 ? "granted" 261 : "denied"; 262 263 // ADVANCED CONSENT MODE ONLY: the `analytics` category decides on its own. 264 // 265 // In Basic mode the granted-wins merge above is right. `performance` is an 266 // analytics-class category, so granting it is a consent to analytics-class 267 // storage, and the tags belonging to `analytics` are hard-blocked by the 268 // script gate regardless of what this signal says â the signal cannot let 269 // anything through. 270 // 271 // Advanced mode removes exactly that backstop: Consent-Mode-aware Google 272 // tags (gtag.js / GA4 / Ads) are deliberately allowed to load 273 // (class-frontend.php, is_gcm_managed_script) so they can send modeled 274 // pings. GA4 is classified `analytics`. So a visitor who denied Analytics 275 // and granted Performance had GA4 loaded AND told analytics_storage was 276 // granted, and it wrote its cookies against that denial â the signal became 277 // the only control, and it was pointing the wrong way. 278 // 279 // Deliberately keyed on the `analytics` category rather than made 280 // most-restrictive: the exempted tags are Google's own and that is the 281 // category they belong to, so an install that offers only `performance` 282 // keeps working (analytics absent -> the merge above still decides), while 283 // one that offers both honours the decision made about the tag actually 284 // running. 285 if (data.advanced_mode) { 286 var analyticsRaw = cookieObj ? cookieObj.analytics : undefined; 287 if ("granted" === analyticsRaw || "denied" === analyticsRaw) { 288 analytics = analyticsRaw; 289 } 290 } 291 // Non-personalized ads fallback: when enabled and marketing is denied, we 292 // do NOT grant ad_storage (that would set ad cookies without consent â 293 // unlawful in EEA/UK/CH). ad_storage stays "denied"; Consent Mode v2 serves 294 // non-personalized, cookieless ads in that state. For legacy ad tags that 295 // don't read Consent Mode we signal `npa` (two-sided: set to 0 when 296 // marketing is later granted so it self-clears within the session). 297 setNpaIfDenied(marketing); 298 return { 299 ad_storage: marketing, 300 analytics_storage: analytics, 301 functionality_storage: fazCat(cookieObj, "functional"), 302 personalization_storage: fazCat(cookieObj, "functional"), 303 security_storage: fazCat(cookieObj, "necessary"), 304 ad_user_data: marketing, 305 ad_personalization: marketing, 306 }; 307} 308 309function updateConsentState(consentState) { 310 gtag("consent", "update", consentState); 311} 312 313// NOTE: the baseline `consent default` (region / denied) has already been 314// emitted above, and a returning visitor's stored grants were restored via 315// `consent update`. We only need to handle live consent changes below. 316 317// Re-apply on consent changes (banner interaction). 318document.addEventListener("fazcookie_consent_update", function () { 319 var updated = parseConsentCookie(); 320 if (!updated) { 321 // parseConsentCookie() returns null when the cookie is stale (server 322 // bumped consent_revision since it was written) or malformed. In that 323 // window there is nothing actionable to push to gtag: leave the 324 // previous consent state untouched and skip GACM too, otherwise we 325 // would clobber the live provider list with "1~" (empty). 326 return; 327 } 328 updateConsentState(buildConsentState(updated)); 329 // Also update GACM additional consent string if enabled. 330 if (data.gacm_enabled && data.gacm_provider_ids) { 331 setAdditionalConsent(updated); 332 } 333}); 334 335// Google Additional Consent Mode (GACM). 336// The Additional Consent string format: "1~id.id.id..." 337// Version 1 + tilde + dot-separated ATP IDs the user consented to. 338function setAdditionalConsent(consentObj) { 339 if (!data.gacm_enabled) return; 340 var providerRaw = data.gacm_provider_ids; 341 var providerStr = typeof providerRaw === "string" ? providerRaw.trim() : ""; 342 if (!providerStr) return; 343 344 // Only include provider IDs when marketing consent is granted. 345 var adsGranted = consentObj && consentObj.marketing === "granted"; 346 var acString; 347 if (adsGranted) { 348 // Include all configured provider IDs.
349 acString = "1~" + providerStr.split(/[,\s]+/).filter(Boolean).join("."); 350 } else { 351 // No consent - empty provider list. 352 acString = "1~"; 353 } 354 355 gtag("set", "addtl_consent", acString); 356} 357 358// Apply GACM on page load if enabled. 359if (data.gacm_enabled && data.gacm_provider_ids) { 360 setAdditionalConsent(initialCookieObj); 361} 362 363})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.