1/** 2 * First-touch campaign attribution capture, plus the consent gate both this 3 * and the conversion event honour. 4 * 5 * Deliberately self-contained: it has no dependency on anything else in this 6 * plugin and knows nothing about the CRM, so it can be lifted into a 7 * site-wide tracking plugin unchanged if that becomes its better home. 8 * 9 * Exposes window.wpfxboAttribution: 10 * .read() - the stored attribution values 11 * .hasConsent() - whether storing/sending is currently permitted 12 * .onConsent( fn ) - run fn once consent is (or becomes) available 13 */ 14(function () { 15 var config = window.wpfxboTracking || {}; 16 var STORAGE_KEY = config.storageKey || 'wpfxbo_attribution'; 17 var CONSENT_MODE = config.consentMode || 'off'; 18 var CONSENT_CATEGORY = config.consentCategory || 'advertisement'; 19 20 var URL_PARAMS = [ 21 'utm_source', 22 'utm_medium', 23 'utm_campaign', 24 'gclid', 25 'wbraid', 26 'gbraid', 27 'fbclid', 28 ]; 29 30 function debug(message) { 31 if (config.debug && window.console) { 32 window.console.warn('[wpfxbo] ' + message); 33 } 34 } 35 36 function getCookie(name) { 37 var match = document.cookie.match(new RegExp('(^|;\\s*)' + name + '=([^;]*)')); 38 return match ? decodeURIComponent(match[2]) : ''; 39 } 40 41 /** 42 * Whether the visitor has agreed to the category these values fall under. 43 * 44 * "off" - no consent framework on the site; nothing to wait for. 45 * "cookieyes" - read CookieYes' own consent cookie, which stores a 46 * "category:yes|no" list. 47 * "callback" - defer entirely to a site-supplied global function, for any 48 * other consent platform. 49 */ 50 function hasConsent() { 51 if (CONSENT_MODE === 'off') { 52 return true; 53 } 54 55 if (CONSENT_MODE === 'callback') { 56 var name = config.consentCallback || ''; 57 var fn = name ? window[name] : null; 58 59 if (typeof fn !== 'function') { 60 debug('consent callback "' + name + '" is not defined; treating as no consent.'); 61 return false; 62 } 63 64 return !!fn(CONSENT_CATEGORY); 65 } 66 67 if (CONSENT_MODE === 'cookieyes') { 68 var consent = getCookie('cookieyes-consent'); 69 70 if (!consent) { 71 return false; 72 } 73 74 return consent.indexOf(CONSENT_CATEGORY + ':yes') !== -1; 75 } 76 77 return false; 78 } 79 80 function readStored() { 81 try { 82 return JSON.parse(window.localStorage.getItem(STORAGE_KEY)) || {}; 83 } catch (e) { 84 return {}; 85 } 86 } 87 88 function writeStored(values) { 89 try { 90 window.localStorage.setItem(STORAGE_KEY, JSON.stringify(values)); 91 } catch (e) { 92 // Private browsing or storage disabled: attribution just won't persist. 93 } 94 } 95 96 /** 97 * Capture first-touch attribution. Values already stored win, so the 98 * original landing URL's campaign data survives later internal navigation. 99 */ 100 function capture() { 101 if (!hasConsent()) { 102 return; 103 } 104 105 var stored = readStored(); 106 var params = new URLSearchParams(window.location.search); 107 var changed = false; 108 109 URL_PARAMS.forEach(function (key) { 110 var value = params.get(key); 111 if (value && !stored[key]) { 112 stored[key] = value; 113 changed = true; 114 } 115 }); 116 117 if (changed) { 118 writeStored(stored); 119 } 120 } 121 122 /** 123 * Run a callback as soon as consent is available - immediately if it 124 * already is, otherwise when the consent platform reports a change. 125 */ 126 function onConsent(callback) { 127 if (hasConsent()) { 128 callback(); 129 return; 130 } 131 132 if (CONSENT_MODE === 'off') { 133 return; 134 } 135 136 var settled = false; 137 var check = function () { 138 if (!settled && hasConsent()) { 139 settled = true; 140 callback(); 141 } 142 }; 143 144 // CookieYes dispatches this once the visitor makes a choice. The 145 // generic consent-update name is listened for too, so another platform 146 // wired through the "callback" mode can reuse the same signal. 147 document.addEventListener('cookieyes_consent_update', check); 148 document.addEventListener('wpfxbo_consent_update', check); 149 } 150 151 window.wpfxboAttribution = { 152 read: readStored, 153 hasConsent: hasConsent, 154 onConsent: onConsent, 155 getCookie: getCookie, 156 debug: debug, 157 }; 158 159 // The URL's campaign values are only present on this page load, so capture 160 // them now and again if consent arrives while the visitor is still here. 161 capture(); 162 onConsent(capture); 163})();
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.