1/* global pysOptions */ 2 3 4! function ($, options) { 5 if (options.debug) { 6 console.log('PYS:', options); 7 } 8 var uniqueId = {}; 9 10 let gtm_variables = {}; 11 let gtm_datalayername = "dynamicVariable"; 12 13 var domain = ''; 14 if(options.hasOwnProperty("track_cookie_for_subdomains") && options.track_cookie_for_subdomains) { 15 domain = getRootDomain(true); 16 } 17 18 // Per-page referrer for Facebook CAPI events. Captured once per script 19 // load so SPA-style navigations within the same HTML document do not 20 // overwrite it. Internal/external is NOT filtered â Meta expects this 21 // field to describe the URL of the previous page for THIS event. 22 var pageReferrer = ''; 23 try { 24 pageReferrer = stripUrlQuery((document.referrer || '').toString()); 25 } catch (e) {} 26 27 // Session-entry referrer (fallback). Captured at session start the first 28 // time the visitor lands from an EXTERNAL site, mirrored to a session 29 // cookie so PHP can read it for orphan events (async/cron) that arrive 30 // without a per-page payload. Never the primary source.
31 var PYS_SESSION_ENTRY_REFERRER_KEY = 'pys_session_entry_referrer'; 32 function stripUrlQuery(url) { 33 if (!url) return ''; 34 var clean = String(url); 35 var q = clean.indexOf('?'); 36 if (q !== -1) clean = clean.substring(0, q); 37 var h = clean.indexOf('#'); 38 if (h !== -1) clean = clean.substring(0, h); 39 return clean; 40 } 41 var sessionEntryReferrer = ''; 42 function getOrInitSessionEntryReferrer(consentGranted) { 43 var value = ''; 44 try { 45 if (typeof window.sessionStorage !== 'undefined') { 46 value = window.sessionStorage.getItem(PYS_SESSION_ENTRY_REFERRER_KEY) || ''; 47 } 48 } catch (e) {} 49 50 if (!value) { 51 var cookieValue = Cookies.get(PYS_SESSION_ENTRY_REFERRER_KEY); 52 if (cookieValue && cookieValue !== 'undefined') { 53 value = cookieValue; 54 try { 55 if (typeof window.sessionStorage !== 'undefined') { 56 window.sessionStorage.setItem(PYS_SESSION_ENTRY_REFERRER_KEY, value); 57 } 58 } catch (e) {} 59 } 60 } 61 62 if (!value) { 63 var raw = ''; 64 try { 65 raw = stripUrlQuery((document.referrer || '').toString()); 66 } catch (e) {} 67 if (raw) { 68 var refHost = ''; 69 try { 70 refHost = new URL(raw).hostname; 71 } catch (e) {} 72 if (refHost && refHost !== window.location.hostname) { 73 value = raw; 74 try { 75 if (typeof window.sessionStorage !== 'undefined') { 76 window.sessionStorage.setItem(PYS_SESSION_ENTRY_REFERRER_KEY, value); 77 } 78 } catch (e) {} 79 } 80 } 81 } 82 83 // Mirror to a session cookie only once consent is given. The cookie 84 // is session-scoped (no expires) and dies with the browser, just 85 // like the sessionStorage entry. 86 if (value && consentGranted && options && options.cookie 87 && !options.cookie.disabled_all_cookie) { 88 var existingCookie = Cookies.get(PYS_SESSION_ENTRY_REFERRER_KEY); 89 if (!existingCookie || existingCookie === 'undefined') { 90 Cookies.set(PYS_SESSION_ENTRY_REFERRER_KEY, value, { path: '/', domain: domain }); 91 } 92 } 93 94 sessionEntryReferrer = value; 95 return value; 96 } 97 98 // Populate sessionStorage / sessionEntryReferrer immediately. Cookie 99 // mirroring is deferred to the consent-gated path in Facebook.loadPixel(). 100 getOrInitSessionEntryReferrer(false); 101 102 // Per-page event referrer (session cookie). Snapshot of document.referrer 103 // for the CURRENT page, refreshed on every page load. Read server-side 104 // by saveFbTagsInOrder() to capture the buyer's checkout-page referrer 105 // for orphan CAPI events (APT, gateway webhooks, manual status changes). 106 // Internal URLs are intentionally NOT filtered â the goal is the page 107 // that led the buyer to checkout, which is usually internal. 108 // If document.referrer is empty (direct navigation), the previous value 109 // is preserved so a session that began with an external referrer keeps 110 // it across same-tab navigations. 111 var PYS_EVENT_REFERRER_KEY = 'pys_event_referrer'; 112 function writeEventReferrerCookie() { 113 if (!pageReferrer) { 114 return; 115 } 116 if (!options || !options.cookie || options.cookie.disabled_all_cookie) { 117 return; 118 } 119 try { 120 Cookies.set(PYS_EVENT_REFERRER_KEY, pageReferrer, { path: '/', domain: domain }); 121 } catch (e) {} 122 } 123 /** 124 * Resolve parameter value based on mode (static or dynamic) 125 * 126 * @param {Object|string} param - Parameter object with { value, selector } or string value 127 * @param {string} key - Parameter key name 128 * @returns {string|null} - Resolved value 129 */ 130 function resolveParamValue(param, key = '') { 131 // 1ï¸â£ null / undefined - skip this parameter 132 if (param === null || param === undefined) { 133 return null; 134 } 135 136 // 2ï¸â£ Handle primitive types (string, number, boolean) 137 if (typeof param !== 'object') { 138 return param; 139 } 140 141 // 3ï¸â£ Handle arrays - process each element recursively 142 if (Array.isArray(param)) { 143 return param.map(item => resolveParamValue(item, key)); 144 } 145 146 // 4ï¸â£ Check if this is a configuration object (has value/selector/dynamic/input_type) 147 const isConfigObject = 148 ('value' in param || 'selector' in param || 'dynamic' in param || 'input_type' in param) && 149 Object.keys(param).every(k => 150 ['value', 'selector', 'dynamic', 'input_type', 'name'].includes(k) 151 ); 152 153 if (isConfigObject) { 154 // STATIC MODE: selector is empty or dynamic is false 155 const isStatic = 156 (!param.dynamic || param.dynamic === false) || 157 (!param.selector || param.selector.trim() === ''); 158 159 if (isStatic) { 160 let value = param.value ?? null; 161 162 // Apply numeric conversion if needed 163 if (param.input_type === "float" || param.input_type === "int") { 164 value = extractNumericValue(value, param.input_type === "int"); 165 } 166 167 return value; 168 } 169 170 // DYNAMIC MODE: selector is present 171 try { 172 const el = document.querySelector(param.selector); 173 if (!el) { 174 return null; 175 } 176 177 let value = 178 el.value || 179 el.innerText || 180 el.textContent || 181 el.getAttribute("content") || 182 el.getAttribute("data-value") || 183 null; 184 185 // Apply numeric conversion if needed 186 if (param.input_type === "float" || param.input_type === "int") { 187 value = extractNumericValue(value, param.input_type === "int"); 188 } 189 190 return value; 191 } catch (e) { 192 return null; 193 } 194 } 195 196 // 5ï¸â£ Plain object (like ecommerce data) - recursively process nested values 197 return Object.fromEntries( 198 Object.entries(param) 199 .map(([k, v]) => [k, resolveParamValue(v, k)]) 200 .filter(([k, v]) => v !== null && v !== undefined) 201 ); 202 } 203 204 function extractNumericValue(value, isInt = false) { 205 if (value === null || value === undefined) { 206 return null; 207 } 208 if (isInt) { 209 return parseInt(value); 210 } 211 return parseFloat(value); 212 } 213 var dummyPinterest = function () { 214 215 /** 216 * Public API 217 */ 218 return { 219 isEnabled: function () {}, 220 disable: function () {}, 221 loadPixel: function () {}, 222 fireEvent: function (name, data) { 223 return false;
224 }, 225 onCommentEvent: function () {}, 226 onDownloadEvent: function (params) {}, 227 onFormEvent: function (params) {}, 228 onWooAddToCartOnButtonEvent: function (product_id) {}, 229 onWooAddToCartOnSingleEvent: function (product_id, qty, is_variable, is_external, $form) {}, 230 onWooRemoveFromCartEvent: function (cart_item_hash) {}, 231 onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) {}, 232 onEddRemoveFromCartEvent: function (item) {}, 233 onPageScroll: function (event) {}, 234 onTime: function (event) {}, 235 236 } 237 238 }(); 239 240 var dummyBing = function () { 241 242 /** 243 * Public API 244 */ 245 return { 246 isEnabled: function () {}, 247 disable: function () {}, 248 loadPixel: function () {}, 249 fireEvent: function (name, data) { 250 return false; 251 }, 252 onAdSenseEvent: function () {}, 253 onClickEvent: function (params) {}, 254 onWatchVideo: function (params) {}, 255 onCommentEvent: function () {}, 256 onFormEvent: function (params) {}, 257 onDownloadEvent: function (params) {}, 258 onWooAddToCartOnButtonEvent: function (product_id) {}, 259 onWooAddToCartOnSingleEvent: function (product_id, qty, is_variable, is_external, $form) {}, 260 onWooRemoveFromCartEvent: function (cart_item_hash) {}, 261 onWooAffiliateEvent: function (product_id) {}, 262 onWooPayPalEvent: function () {}, 263 onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) {}, 264 onEddRemoveFromCartEvent: function (item) {}, 265 onPageScroll: function (event) {}, 266 onTime: function (event) {}, 267 } 268 269 }(); 270 271 var dummyReddit = function () { 272 /** 273 * Public API 274 */ 275 return { 276 tag: function () { 277 return "reddit"; 278 }, 279 isEnabled: function () {}, 280 disable: function () {}, 281 loadPixel: function () {}, 282 fireEvent: function ( name, data ) { 283 return false; 284 }, 285 onAdSenseEvent: function ( event ) {}, 286 onClickEvent: function ( params ) {}, 287 onWatchVideo: function ( params ) {}, 288 onCommentEvent: function ( event ) {}, 289 onFormEvent: function ( params ) {}, 290 onDownloadEvent: function ( params ) {}, 291 onWooAddToCartOnButtonEvent: function ( product_id ) {}, 292 onWooAddToCartOnSingleEvent: function ( product_id, qty, product_type, is_external, $form ) {}, 293 onWooRemoveFromCartEvent: function ( cart_item_hash ) {}, 294 onWooAffiliateEvent: function ( product_id ) {}, 295 onWooPayPalEvent: function ( event ) {}, 296 onEddAddToCartOnButtonEvent: function ( download_id, price_index, qty ) {}, 297 onEddRemoveFromCartEvent: function ( item ) {}, 298 onPageScroll: function ( event ) {}, 299 onTime: function ( event ) {}, 300 } 301 }(); 302 303 304 var Utils = function (options) { 305 306 var Pinterest = dummyPinterest; 307 308 var Bing = dummyBing; 309 310 var Reddit = dummyReddit; 311 312 var gtag_loaded = false; 313 314 var gtm_loaded = false; 315 316 let isNewSession = checkSession(); 317 318 var utmTerms = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']; 319 320 var utmId = ['fbadid', 'gadid', 'padid', 'bingid']; 321 322 let dataLayerName = 'dataLayerPYS'; 323 324 let GTMdataLayerName = 'dataLayer'; 325 326 function validateEmail(email) { 327 var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 328 return re.test(email); 329 } 330 function getDomain(url) { 331 332 url = url.replace(/(https?:\/\/)?(www.)?/i, ''); 333 334 if (url.indexOf('/') !== -1) { 335 return url.split('/')[0]; 336 } 337 338 return url; 339 } 340 function loadPixels() { 341 342 if (!options.gdpr.all_disabled_by_api) { 343 344 if (!options.gdpr.facebook_disabled_by_api) { 345 Facebook.loadPixel(); 346 } 347 348 if (!options.gdpr.analytics_disabled_by_api) { 349 Analytics.loadPixel(); 350 } 351 352 if (!options.gdpr.analytics_disabled_by_api) { 353 GTM.loadPixel(); 354 } 355 356 if (!options.gdpr.pinterest_disabled_by_api) { 357 Pinterest.loadPixel(); 358 } 359 360 if (!options.gdpr.bing_disabled_by_api) { 361 Bing.loadPixel(); 362 } 363 364 if (!options.gdpr.reddit_disabled_by_api) { 365 Reddit.loadPixel(); 366 } 367 } 368 if (options.gdpr.consent_magic_integration_enabled && typeof CS_Data !== "undefined") { 369 if (typeof CS_Data.cs_google_analytics_consent_mode !== "undefined" && CS_Data.cs_google_analytics_consent_mode == 1) { 370 Analytics.loadPixel(); 371 } 372 } 373 374 } 375 376 function checkSession() { 377 if( Cookies.get('pys_start_session') === undefined || 378 Cookies.get('pys_session_limit') === undefined) { 379 firstVisit = true; 380 return true 381 } 382 return false 383 384 } 385 386 function getTrafficSource() { 387 388 try { 389 390 let referrer = stripUrlQuery(document.referrer.toString()), 391 source; 392 393 let direct = referrer.length === 0; 394 let internal = direct ? false : referrer.indexOf(options.siteUrl) === 0; 395 let external = !direct && !internal; 396 397 if (external === false) { 398 source = 'direct'; 399 } else { 400 source = referrer; 401 } 402 403 if (source !== 'direct') { 404 // leave only domain (Issue #70) 405 return getDomain(source); 406 } else { 407 return source; 408 } 409 410 } catch (e) { 411 console.error(e); 412 return 'direct'; 413 } 414 415 } 416 417 /** 418 * Return query variables object with where property name is query variable 419 * and property value is query variable value. 420 */ 421 function getQueryVars() { 422 423 try { 424 425 var result = {}, 426 tmp = []; 427 428 window.location.search 429 .substr(1) 430 .split("&") 431 .forEach(function (item) { 432 433 tmp = item.split('='); 434 435 if (tmp.length > 1) { 436 result[tmp[0]] = tmp[1]; 437 } 438 439 }); 440 441 return result; 442 443 } catch (e) { 444 console.error(e); 445 return {}; 446 } 447 448 } 449 450 451 function getLandingPageValue() { 452 let name = "pys_landing_page" 453 if(options.visit_data_model === "last_visit") { 454 name = "last_pys_landing_page" 455 } 456 if(Cookies.get(name) && Cookies.get(name) !== "undefined") { 457 return Cookies.get(name); 458 } 459 else if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.TrafficLanding){ 460 return options.tracking_analytics.TrafficLanding; 461 } else{ 462 return ""; 463 } 464 } 465 function getTrafficSourceValue() { 466 let name = "pysTrafficSource" 467 if(options.visit_data_model === "last_visit") { 468 name = "last_pysTrafficSource" 469 } 470 if(Cookies.get(name) && Cookies.get(name) !== "undefined") { 471 return Cookies.get(name); 472 } else{ 473 return ""; 474 } 475 } 476 477 function getUTMId(useLast = false) { 478 try { 479 let cookiePrefix = 'pys_' 480 let terms = []; 481 if (useLast) { 482 cookiePrefix = 'last_pys_' 483 } 484 $.each(utmId, function (index, name) { 485 if (Cookies.get(cookiePrefix + name)) { 486 terms[name] = Cookies.get(cookiePrefix + name) 487 } 488 else if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.TrafficUtmsId[name]) { 489 terms[name] = filterEmails(options.tracking_analytics.TrafficUtmsId[name]) 490 } 491 }); 492 return terms; 493 } catch (e) { 494 console.error(e); 495 return []; 496 } 497 } 498 /** 499 * Return UTM terms from request query variables or from cookies. 500 */ 501 function getUTMs(useLast = false) { 502 503 try { 504 let cookiePrefix = 'pys_' 505 if(useLast) { 506 cookiePrefix = 'last_pys_' 507 } 508 let terms = []; 509 $.each(utmTerms, function (index, name) { 510 if (Cookies.get(cookiePrefix + name)) { 511 let value = Cookies.get(cookiePrefix + name); 512 terms[name] = filterEmails(value); // do not allow email in request params (Issue #70) 513 } 514 else if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.TrafficUtms[name]) { 515 terms[name] = filterEmails(options.tracking_analytics.TrafficUtms[name]) 516 } 517 }); 518 519 return terms; 520 521 } catch (e) { 522 console.error(e); 523 return []; 524 } 525 526 } 527 528 function getDateTime() { 529 var dateTime = new Array(); 530 var date = new Date(), 531 days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], 532 months = ['January', 'February', 'March', 'April', 'May', 'June', 533 'July', 'August', 'September', 'October', 'November', 'December' 534 ], 535 hours = ['00-01', '01-02', '02-03', '03-04', '04-05', '05-06', '06-07', '07-08', 536 '08-09', '09-10', '10-11', '11-12', '12-13', '13-14', '14-15', '15-16', '16-17', 537 '17-18', '18-19', '19-20', '20-21', '21-22', '22-23', '23-24' 538 ]; 539 dateTime.push(hours[date.getHours()]); 540 dateTime.push(days[date.getDay()]); 541 dateTime.push(months[date.getMonth()]); 542 return dateTime; 543 } 544 545 function filterEmails(value) { 546 return validateEmail(value) ? undefined : value; 547 } 548 549 /** 550 * PUBLIC API 551 */ 552 return { 553 PRODUCT_SIMPLE : 0, 554 PRODUCT_VARIABLE : 1, 555 PRODUCT_BUNDLE : 2, 556 PRODUCT_GROUPED : 3, 557 utmTerms : utmTerms, 558 utmId : utmId, 559 fireEventForAllPixel:function(functionName,events){ 560 if (events.hasOwnProperty(Facebook.tag())) 561 Facebook[functionName](events[Facebook.tag()]); 562 if (events.hasOwnProperty(Analytics.tag())) 563 Analytics[functionName](events[Analytics.tag()]); 564 if (events.hasOwnProperty(Pinterest.tag())) 565 Pinterest[functionName](events[Pinterest.tag()]); 566 if (events.hasOwnProperty(Bing.tag())) 567 Bing[functionName](events[Bing.tag()]); 568 if (events.hasOwnProperty(Reddit.tag())) 569 Reddit[functionName](events[Reddit.tag()]); 570 571 if (events.hasOwnProperty(GTM.tag())) 572 GTM[functionName](events[GTM.tag()]); 573 }, 574 575 setupPinterestObject: function () { 576 Pinterest = window.pys.Pinterest || Pinterest; 577 return Pinterest; 578 }, 579 580 setupBingObject: function () { 581 Bing = window.pys.Bing || Bing; 582 return Bing; 583 }, 584 585 setupRedditObject: function () { 586 Reddit = window.pys.Reddit || Reddit; 587 return Reddit; 588 }, 589 590 // Clone all object members to another and return it 591 copyProperties: function (from, to) { 592 for (var key in from) { 593 if("function" == typeof from[key]) { 594 continue; 595 } 596 to[key] = from[key]; 597 } 598 return to; 599 }, 600 601 manageCookies: function () { 602 603 if (options.gdpr.cookiebot_integration_enabled && typeof Cookiebot !== 'undefined') { 604 if (Cookiebot.consented === false && !Cookiebot.consent['marketing'] && !Cookiebot.consent['statistics']) { 605 return; 606 } 607 } 608 let cm_consent_not_expressed = false;
609 if ( options.gdpr.consent_magic_integration_enabled && window.CS_Data !== undefined && window.CS_Data.cs_refresh_after_consent == 1 ) { 610 if ( Cookies.get( 'cs_viewed_cookie_policy' ) === undefined ) { 611 cm_consent_not_expressed = true; 612 } 613 } 614 615 if( !cm_consent_not_expressed && isNewSession && !options.cookie.disabled_all_cookie && !options.cookie.disabled_start_session_cookie) { 616 let duration = options.last_visit_duration * 60000 617 var now = new Date(); 618 now.setTime(now.getTime() + duration); 619 Cookies.set('pys_session_limit', true,{ expires: now, path: '/',domain: domain }) 620 Cookies.set('pys_start_session', true,{path: '/',domain: domain}); 621 } 622 623 if (options.ajaxForServerEvent && !Cookies.get('pbid') && Facebook.isEnabled()) { 624 jQuery.ajax({ 625 url: options.ajaxUrl, 626 dataType: 'json', 627 data: { 628 action: 'pys_get_pbid' 629 }, 630 success: function (res) { 631 if (res.data && res.data.pbid != false && options.send_external_id) { 632 if(!(options.cookie.disabled_all_cookie || options.cookie.externalID_disabled_by_api)){ 633 var expires = parseInt(options.external_id_expire || 180); 634 Cookies.set('pbid', res.data.pbid, { expires: expires, path: '/',domain: domain }); 635 } 636 637 if(options.hasOwnProperty('facebook')) { 638 options.facebook.advancedMatching = { 639 ...options.facebook.advancedMatching, // spread current advancedMatching values 640 external_id: res.data.pbid 641 }; 642 } 643 } 644 } 645 }); 646 } else if (Cookies.get('pbid') && Facebook.isEnabled()){ 647 if(Facebook.advancedMatching() && Facebook.advancedMatching().external_id && !(options.cookie.disabled_all_cookie || options.cookie.externalID_disabled_by_api)){ 648 let expires = parseInt(options.external_id_expire || 180); 649 Cookies.set('pbid', Facebook.advancedMatching().external_id, { expires: expires, path: '/',domain: domain }); 650 } 651 } 652 653 let expires = parseInt(options.cookie_duration); // days 654 let queryVars = getQueryVars(); 655 let landing = window.location.href.split('?')[0]; 656 try { 657 // save data for first visit 658 if(Cookies.get('pys_first_visit') === undefined && (!options.cookie.disabled_all_cookie)) { 659 660 if(!options.cookie.disabled_first_visit_cookie) 661 { 662 Cookies.set('pys_first_visit', true, { expires: expires, path: '/',domain: domain }); 663 } 664 else { 665 Cookies.remove('pys_first_visit') 666 } 667 668 if(!options.cookie.disabled_trafficsource_cookie) 669 { 670 Cookies.set('pysTrafficSource', getTrafficSource(), { expires: expires,path: '/',domain: domain }); 671 } 672 else { 673 Cookies.remove('pysTrafficSource') 674 } 675 676 if(!options.cookie.disabled_landing_page_cookie) 677 { 678 Cookies.set('pys_landing_page',landing,{ expires: expires,path: '/',domain: domain }); 679 } 680 else { 681 Cookies.remove('pys_landing_page') 682 } 683 684 if(!options.cookie.disabled_utmTerms_cookie) 685 { 686 $.each(utmTerms, function (index, name) { 687 if (queryVars.hasOwnProperty(name)) { 688 Cookies.set('pys_' + name, queryVars[name], { expires: expires,path: '/',domain: domain }); 689 } else { 690 Cookies.remove('pys_' + name) 691 } 692 }); 693 } 694 else { 695 $.each(utmTerms, function (index, name) { 696 Cookies.remove('pys_' + name) 697 }); 698 } 699 700 if(!options.cookie.disabled_utmId_cookie) 701 { 702 $.each(utmId,function(index,name) { 703 if (queryVars.hasOwnProperty(name)) { 704 Cookies.set('pys_' + name, queryVars[name], { expires: expires,path: '/',domain: domain }); 705 } else { 706 Cookies.remove('pys_' + name) 707 } 708 }) 709 } 710 else { 711 $.each(utmId, function (index, name) { 712 Cookies.remove('pys_' + name) 713 }); 714 } 715 } 716 717 // save data for last visit if it new session 718 if(isNewSession && (!options.cookie.disabled_all_cookie)) { 719 if(!options.cookie.disabled_trafficsource_cookie) 720 { 721 Cookies.set('last_pysTrafficSource', getTrafficSource(), { expires: expires,path: '/',domain: domain }); 722 } 723 else { 724 Cookies.remove('last_pysTrafficSource') 725 } 726 727 if(!options.cookie.disabled_landing_page_cookie) 728 { 729 Cookies.set('last_pys_landing_page',landing,{ expires: expires,path: '/',domain: domain }); 730 } 731 else { 732 Cookies.remove('last_pys_landing_page') 733 } 734 735 if(!options.cookie.disabled_utmTerms_cookie) 736 { 737 $.each(utmTerms, function (index, name) { 738 if (queryVars.hasOwnProperty(name)) { 739 Cookies.set('last_pys_' + name, queryVars[name], { expires: expires,path: '/',domain: domain }); 740 } else { 741 Cookies.remove('last_pys_' + name) 742 } 743 }); 744 } 745 else { 746 $.each(utmTerms, function (index, name) { 747 Cookies.remove('last_pys_' + name) 748 }); 749 } 750 751 if(!options.cookie.disabled_utmId_cookie) 752 { 753 $.each(utmId,function(index,name) { 754 if (queryVars.hasOwnProperty(name)) { 755 Cookies.set('last_pys_' + name, queryVars[name], { expires: expires,path: '/',domain: domain }); 756 } else { 757 Cookies.remove('last_pys_' + name) 758 } 759 }) 760 } 761 else { 762 $.each(utmId, function (index, name) { 763 Cookies.remove('last_pys_' + name) 764 }); 765 } 766 767 } 768 if(options.cookie.disabled_start_session_cookie) { 769 Cookies.remove('pys_start_session') 770 Cookies.remove('pys_session_limit') 771 } 772 if(options.cookie.disabled_all_cookie) 773 { 774 Cookies.remove('pys_first_visit') 775 Cookies.remove('pysTrafficSource') 776 Cookies.remove('pys_landing_page') 777 Cookies.remove('last_pys_landing_page') 778 Cookies.remove('last_pysTrafficSource') 779 Cookies.remove('pys_start_session') 780 Cookies.remove('pys_session_limit') 781 $.each(Utils.utmTerms, function (index, name) { 782 Cookies.remove('pys_' + name) 783 }); 784 $.each(Utils.utmId,function(index,name) { 785 Cookies.remove('pys_' + name) 786 }) 787 $.each(Utils.utmTerms, function (index, name) { 788 Cookies.remove('last_pys_' + name) 789 }); 790 $.each(Utils.utmId,function(index,name) { 791 Cookies.remove('last_pys_' + name) 792 }); 793 } 794 } catch (e) { 795 console.error(e); 796 } 797 }, 798 /** 799 * Generate unique ID 800 */ 801 generateUniqueId : function (event) { 802 if(event.eventID.length == 0 || (event.type == "static" && options.ajaxForServerStaticEvent) || (event.type !== "static" && options.ajaxForServerEvent)) { 803 let idKey = event.hasOwnProperty('custom_event_post_id') ? event.custom_event_post_id : event.e_id; 804 if (!uniqueId.hasOwnProperty(idKey)) { 805 uniqueId[idKey] = pys_generate_token(); 806 } 807 return uniqueId[idKey]; 808 } 809 else if(event.eventID.length !== 0) 810 { 811 return event.eventID; 812 } 813 }, 814 815 // Flatten object for sendBeacon compatibility 816 flattenObject: function (obj, prefix = '', res = {}) { 817 for (const [key, value] of Object.entries(obj)) { 818 const prefixedKey = prefix 819 ? (Array.isArray(obj) ? `${prefix}[${key}]` : `${prefix}[${key}]`)
820 : key; 821 if (value !== null && typeof value === 'object' && !(value instanceof File)) { 822 this.flattenObject(value, prefixedKey, res); 823 } else { 824 res[prefixedKey] = value; 825 } 826 } 827 return res; 828 }, 829 830 sendServerAjaxRequest : function(url, data) { 831 if (data.action === 'pys_api_event' && data.pixel === 'facebook' && window.pysFacebookRest) { 832 // Use Facebook REST API 833 this.sendRestAPIRequest(data, 'facebook'); 834 return; 835 } 836 837 // Check if sendBeacon is enabled and supported 838 if (options.useSendBeacon && navigator.sendBeacon) { 839 try { 840 // Flatten the data object for sendBeacon compatibility 841 const flattenedData = this.flattenObject(data); 842 const formData = new URLSearchParams(); 843 844 // Convert flattened data to URLSearchParams 845 for (const [key, value] of Object.entries(flattenedData)) { 846 if (value !== null && value !== undefined) { 847 formData.append(key, value); 848 } 849 } 850 851 // Try to send using sendBeacon 852 const success = navigator.sendBeacon(url, formData); 853 if (success) { 854 return; // Successfully sent via sendBeacon 855 } 856 } catch (e) { 857 // If sendBeacon fails, fall back to jQuery.ajax 858 if (options.debug) { 859 console.log('PYS: sendBeacon failed, falling back to jQuery.ajax:', e); 860 } 861 } 862 } 863 864 // Fallback to jQuery.ajax 865 jQuery.ajax( { 866 type: 'POST', 867 url: url, 868 data: data, 869 headers: { 870 'Cache-Control': 'no-cache' 871 }, 872 success: function () { 873 }, 874 } ); 875 }, 876 877 sendRestAPIRequest: function (data, platform) { 878 let restApiUrl; 879 880 // Get platform-specific REST API configuration 881 switch (platform) { 882 case 'facebook': 883 restApiUrl = window.pysFacebookRest ? window.pysFacebookRest.restApiUrl : '/wp-json/pys-facebook/v1/event'; 884 break; 885 default: 886 console.error('PYS: Unknown platform for REST API:', platform); 887 this.sendAjaxFallback(data); 888 return; 889 } 890 891 // Prepare data for REST API 892 const restApiData = { 893 event: data.event, 894 data: JSON.stringify(data.data || {}), 895 ids: JSON.stringify(data.ids || []), 896 eventID: data.event_id || data.eventID || '', 897 woo_order: data.woo_order || '0', 898 edd_order: data.edd_order || '0' 899 }; 900 901 const forwardedReferrer = data.referrer_url || pageReferrer; 902 if (forwardedReferrer) { 903 restApiData.referrer_url = forwardedReferrer; 904 } 905 906 // Variant A: send the actual page URL where the event happened 907 // so the server sets event_source_url to this page, not the 908 // REST endpoint. PHP applies enable_remove_source_url_params. 909 restApiData.event_source_url = data.url || window.location.href; 910 911 // Try to send using sendBeacon first (if enabled) 912 if (options.useSendBeacon && navigator.sendBeacon) { 913 try { 914 const formData = new URLSearchParams(); 915 for (const [key, value] of Object.entries(restApiData)) { 916 formData.append(key, value); 917 } 918 919 if (navigator.sendBeacon(restApiUrl, formData)) { 920 return; 921 } 922 } catch (e) { 923 // sendBeacon failed, continue to fetch 924 } 925 } 926 927 // Try to send using fetch with REST API 928 if (window.fetch) { 929 const headers = { 930 'Content-Type': 'application/json' 931 }; 932 933 fetch(restApiUrl, { 934 method: 'POST', 935 headers: headers, 936 body: JSON.stringify(restApiData) 937 }) 938 .then(response => { 939 if (!response.ok) {
940 throw new Error(platform + ' REST API request failed: ' + response.status); 941 } 942 }) 943 .catch(error => { 944 // Fallback to AJAX if REST API fails 945 if (options.debug) { 946 console.log('PYS: ' + platform + ' REST API failed, falling back to AJAX:', error); 947 } 948 this.sendAjaxFallback(data); 949 }); 950 } else { 951 // Fallback to AJAX if fetch is not supported 952 this.sendAjaxFallback(data); 953 } 954 }, 955 956 957 958 // Fallback AJAX method 959 sendAjaxFallback: function (data) { 960 jQuery.ajax({ 961 type: 'POST', 962 url: options.ajaxUrl, 963 data: data, 964 headers: { 965 'Cache-Control': 'no-cache' 966 }, 967 success: function () { 968 }, 969 }); 970 }, 971 // clone object 972 clone: function(obj) { 973 var copy; 974 975 // Handle the 3 simple types, and null or undefined 976 if (null == obj || "object" != typeof obj) return obj; 977 978 // Handle Date 979 if (obj instanceof Date) { 980 copy = new Date(); 981 copy.setTime(obj.getTime()); 982 return copy; 983 } 984 985 // Handle Array 986 if (obj instanceof Array) { 987 copy = []; 988 for (var i = 0, len = obj.length; i < len; i++) { 989 if("function" == typeof obj[i]) { 990 continue; 991 } 992 copy[i] = Utils.clone(obj[i]); 993 } 994 return copy; 995 } 996 997 // Handle Object 998 if (obj instanceof Object) { 999 copy = {}; 1000 for (var attr in obj) { 1001 if (obj.hasOwnProperty(attr)) { 1002 if("function" == typeof obj[attr]) { 1003 continue; 1004 } 1005 copy[attr] = Utils.clone(obj[attr]); 1006 } 1007 } 1008 return copy; 1009 } 1010 1011 return obj; 1012 }, 1013 1014 // Returns array of elements with given tag name 1015 getTagsAsArray: function (tag) { 1016 return [].slice.call(document.getElementsByTagName(tag)); 1017 }, 1018
1019 getRequestParams: function () { 1020 return []; 1021 }, 1022 1023 /** 1024 * CUSTOM EVENTS 1025 */ 1026 1027 setupMouseOverClickEvents: function (eventId, triggers) { 1028 1029 // Non-default binding used to avoid situations when some code in external js 1030 // stopping events propagation, eg. returns false, and our handler will never called 1031 document.addEventListener('mouseover', function(event) { 1032 var matchedElements = Array.from(document.querySelectorAll(triggers)); 1033 var clickedElement = event.target; 1034 var closestMatch = clickedElement.closest(triggers); 1035 if (matchedElements.includes(clickedElement) || closestMatch){ 1036 if (event.target.classList.contains('pys-mouse-over-' + eventId)) { 1037 return true; 1038 } else { 1039 event.target.classList.add('pys-mouse-over-' + eventId); 1040 } 1041 1042 Utils.fireTriggerEvent(eventId); 1043 } 1044 }); 1045 1046 }, 1047 1048 setupCSSClickEvents: function (eventId, triggers) { 1049 // Non-default binding used to avoid situations when some code in external js 1050 // stopping events propagation, eg. returns false, and our handler will never called 1051 document.addEventListener('click', function(event) { 1052 let matchedElements = Array.from(document.querySelectorAll(triggers)), 1053 clickedElement = event.target, 1054 closestMatch = clickedElement.closest(triggers); 1055 1056 if (matchedElements.includes(clickedElement) || closestMatch){ 1057 Utils.fireTriggerEvent(eventId); 1058 } 1059 }, true); 1060 }, 1061 1062 setupURLClickEvents: function () { 1063 1064 if( !options.triggerEventTypes.hasOwnProperty('url_click') ) { 1065 return; 1066 } 1067 // Non-default binding used to avoid situations when some code in external js 1068 // stopping events propagation, eg. returns false, and our handler will never called 1069 $('a[data-pys-event-id]').onFirst('click', function (evt) { 1070 1071 $(this).attr('data-pys-event-id').split(',').forEach(function (eventId) { 1072 1073 eventId = parseInt(eventId); 1074 1075 if (isNaN(eventId) === false) { 1076 Utils.fireTriggerEvent(eventId); 1077 } 1078 1079 }); 1080 1081 }); 1082 1083 1084 }, 1085 1086 setupScrollPosEvents: function (eventId, triggers) { 1087 1088 var scrollPosThresholds = {}, 1089 docHeight = $(document).height() - $(window).height(); 1090 1091 // convert % to absolute positions 1092 $.each(triggers, function (index, scrollPos) { 1093 1094 // convert % to pixels 1095 scrollPos = docHeight * scrollPos / 100; 1096 scrollPos = Math.round(scrollPos); 1097 1098 scrollPosThresholds[scrollPos] = eventId; 1099 1100 }); 1101 1102 $(document).on("scroll",function () { 1103 1104 var scrollPos = $(window).scrollTop(); 1105 1106 $.each(scrollPosThresholds, function (threshold, eventId) { 1107 1108 // position has not reached yes 1109 if (scrollPos <= threshold) { 1110 return true; 1111 } 1112 1113 // fire event only once 1114 if (eventId === null) { 1115 return true; 1116 } else { 1117 scrollPosThresholds[threshold] = null; 1118 } 1119 1120 Utils.fireTriggerEvent(eventId); 1121 1122 }); 1123 1124 }); 1125 1126 1127 }, 1128 setupCommentEvents : function (eventId,triggers) { 1129 $('form.comment-form').on("submit",function () { 1130 Utils.fireTriggerEvent(eventId); 1131 }); 1132 }, 1133 1134 /** 1135 * Events 1136 */ 1137 1138 fireTriggerEvent: function (eventId) { 1139 1140 if (!options.triggerEvents.hasOwnProperty(eventId)) { 1141 return; 1142 } 1143 1144 var event = {}; 1145 var events = options.triggerEvents[eventId]; 1146 1147 if (events.hasOwnProperty('facebook')) { 1148 event = Utils.getFormFilledData(events.facebook); 1149 Facebook.fireEvent(event.name, event); 1150 } 1151 1152 if (events.hasOwnProperty('ga')) { 1153 event = Utils.getFormFilledData(events.ga); 1154 Analytics.fireEvent(event.name, event); 1155 } 1156 1157 if (events.hasOwnProperty('pinterest')) { 1158 event = Utils.getFormFilledData(events.pinterest); 1159 Pinterest.fireEvent(event.name, event); 1160 } 1161 1162 if (events.hasOwnProperty('bing')) { 1163 event = Utils.getFormFilledData(events.bing); 1164 Bing.fireEvent(event.name, event); 1165 } 1166 1167 if (events.hasOwnProperty('reddit')) { 1168 event = Utils.getFormFilledData(events.reddit); 1169 Reddit.fireEvent(event.name, event); 1170 } 1171 1172 if (events.hasOwnProperty('gtm')) { 1173 event = Utils.getFormFilledData(events.gtm); 1174 GTM.fireEvent(event.name, event); 1175 } 1176 }, 1177 1178 fireStaticEvents: function (pixel) { 1179 1180 if (options.staticEvents.hasOwnProperty(pixel)) { 1181 1182 $.each(options.staticEvents[pixel], function (eventName, events) { 1183 $.each(events, function (index, eventData) { 1184 1185 eventData.fired = eventData.fired || false; 1186 1187 if (!eventData.fired) { 1188 eventData = Utils.getFormFilledData(eventData); 1189 var fired = false;
1190 1191 // fire event 1192 if ('facebook' === pixel) { 1193 fired = Facebook.fireEvent(eventData.name, eventData); 1194 } else if ('ga' === pixel) { 1195 fired = Analytics.fireEvent(eventData.name, eventData); 1196 } else if ('pinterest' === pixel) { 1197 fired = Pinterest.fireEvent(eventData.name, eventData); 1198 } else if ('bing' === pixel) { 1199 fired = Bing.fireEvent(eventData.name, eventData); 1200 } else if ('gtm' === pixel) { 1201 fired = GTM.fireEvent(eventData.name, eventData); 1202 } else if ('reddit' === pixel) { 1203 fired = Reddit.fireEvent(eventData.name, eventData); 1204 } 1205 1206 // prevent event double event firing 1207 eventData.fired = fired; 1208 1209 } 1210 1211 }); 1212 }); 1213 1214 } 1215 1216 }, 1217 1218 /** 1219 * Load tag's JS 1220 * 1221 * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/ 1222 * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/custom-dims-mets 1223 */ 1224 loadGoogleTag: function (id) { 1225 1226 if (!gtag_loaded) { 1227 let dataLayerName = this.dataLayerName; 1228 if(options.hasOwnProperty('GATags')){ 1229 switch (options.GATags.ga_datalayer_type) { 1230 case 'default': 1231 dataLayerName = 'dataLayerPYS'; 1232 break; 1233 case 'custom': 1234 dataLayerName = options.GATags.ga_datalayer_name; 1235 break; 1236 default: 1237 dataLayerName = 'dataLayer'; 1238 } 1239 } 1240 this.dataLayerName = dataLayerName; 1241 (function (window, document, src) { 1242 var a = document.createElement('script'), 1243 m = document.getElementsByTagName('script')[0]; 1244 a.async = 1; 1245 a.src = src; 1246 m.parentNode.insertBefore(a, m); 1247 })(window, document, '//www.googletagmanager.com/gtag/js?id=' + id+'&l='+this.dataLayerName); 1248 1249 window[dataLayerName] = window[dataLayerName] || []; 1250 window.gtag = window.gtag || function gtag() { 1251 window[dataLayerName].push(arguments); 1252 }; 1253 1254 if ( options.google_consent_mode ) { 1255 let data = {}; 1256 data[ 'analytics_storage' ] = options.gdpr.analytics_storage.enabled ? options.gdpr.analytics_storage.value : 'granted'; 1257 data[ 'ad_storage' ] = options.gdpr.ad_storage.enabled ? options.gdpr.ad_storage.value : 'granted'; 1258 data[ 'ad_user_data' ] = options.gdpr.ad_user_data.enabled ? options.gdpr.ad_user_data.value : 'granted'; 1259 data[ 'ad_personalization' ] = options.gdpr.ad_personalization.enabled ? options.gdpr.ad_personalization.value : 'granted'; 1260 1261 this.loadDefaultConsent( 'consent', 'default', data ); 1262 } 1263 1264 gtag('js', new Date()); 1265 gtag_loaded = true; 1266 1267 } 1268 1269 }, 1270 1271 loadDefaultConsent: function() { 1272 window[ this.dataLayerName ].push( arguments ); 1273 }, 1274 1275 loadGTMScript: function (id = '') { 1276 // Strip trailing slash to allow both "domain.com" and "domain.com/" inputs. 1277 const domain = ( options.gtm.gtm_container_domain ?? 'www.googletagmanager.com' ).replace( /\/$/, '' ); 1278 const loader = options.gtm.gtm_container_identifier ?? 'gtm'; 1279 const gtm_auth = options.gtm.gtm_auth ?? ''; 1280 const gtm_preview = options.gtm.gtm_preview ?? ''; 1281 const datalayer_name = options.gtm.gtm_dataLayer_name ?? 'dataLayer'; 1282 1283 window[ datalayer_name ] = window[ datalayer_name ] || []; 1284 window.gtag = window.gtag || function gtag() { 1285 window[ datalayer_name ].push( arguments ); 1286 }; 1287 1288 // Push consent defaults synchronously before the GTM script tag is inserted. 1289 // When PYS loads the GTM snippet itself (non-dataLayer-only mode), this ensures 1290 // defaults are in the dataLayer before GTM processes any events. 1291 this.pushGTMConsentDefaults( datalayer_name ); 1292 1293 (function(w, d, s, l, i) { 1294 w[l] = w[l] || []; 1295 w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' }); 1296 const f = d.getElementsByTagName(s)[0]; 1297 const j = d.createElement(s); 1298 const dl = l !== 'dataLayer' ? '&l=' + l : ''; 1299 j.async = true; 1300 1301 // Detect domain format: bare hostname (legacy) vs full URL / relative path (new). 1302 // Legacy "www.googletagmanager.com" â prepe
1302nd https:// and append .js. 1303 // New format "/metrics" or "https://custom.com" â use as-is. 1304 // Identifier with extension (e.g. "gtm.js") â file: domain/gtm.js?id= 1305 // Identifier without extension (e.g. "g4h25o") â path: domain/g4h25o/?id= 1306 const isNewFormat = domain.startsWith( 'http://' ) 1307 || domain.startsWith( 'https://' ) 1308 || domain.startsWith( '/' ); 1309 1310 if ( !isNewFormat ) { 1311 j.src = 'https://' + domain + '/' + loader + '.js?id=' + i + dl; 1312 } else { 1313 const hasExtension = loader.includes( '.' ); 1314 j.src = domain + '/' + loader + ( hasExtension ? '?' : '/?' ) + 'id=' + i + dl; 1315 } 1316 1317 if (gtm_auth && gtm_preview) { 1318 j.src += '>m_auth=' + gtm_auth + '>m_preview=' + gtm_preview + '>m_cookies_win=x'; 1319 } 1320 f.parentNode.insertBefore(j, f); 1321 })(window, document, 'script', datalayer_name, id); 1322 1323 }, 1324 1325 loadDefaultGTMConsent: function() { 1326 window[ this.GTMdataLayerName ].push( arguments ); 1327 }, 1328 1329 // Extracted helper: push GTM consent defaults to the dataLayer. 1330 // Called from loadGTMScript (when PYS loads the snippet) and from 1331 // GTM.loadPixel when gtm_just_data_layer is enabled, so defaults are 1332 // always present regardless of which code path loads the GTM container. 1333 pushGTMConsentDefaults: function( datalayer_name ) { 1334 if ( !options.google_consent_mode ) { 1335 return; 1336 } 1337 let data = {}; 1338 data[ 'analytics_storage' ] = options.gdpr.analytics_storage.enabled ? options.gdpr.analytics_storage.value : 'granted'; 1339 data[ 'ad_storage' ] = options.gdpr.ad_storage.enabled ? options.gdpr.ad_storage.value : 'granted'; 1340 data[ 'ad_user_data' ] = options.gdpr.ad_user_data.enabled ? options.gdpr.ad_user_data.value : 'granted'; 1341 data[ 'ad_personalization' ] = options.gdpr.ad_personalization.enabled ? options.gdpr.ad_personalization.value : 'granted'; 1342 this.GTMdataLayerName = datalayer_name; 1343 this.loadDefaultGTMConsent( 'consent', 'default', data ); 1344 }, 1345 1346 /** 1347 * GDPR 1348 */ 1349 1350 loadPixels: function () { 1351 1352 if (options.gdpr.ajax_enabled && !options.gdpr.consent_magic_integration_enabled) { 1353 1354 // retrieves actual PYS GDPR filters values which allow to avoid cache issues 1355 $.get({ 1356 url: options.ajaxUrl, 1357 dataType: 'json', 1358 data: { 1359 action: 'pys_get_gdpr_filters_values' 1360 }, 1361 success: function (res) { 1362 1363 if (res.success) { 1364 1365 options.gdpr.all_disabled_by_api = res.data.all_disabled_by_api; 1366 options.gdpr.facebook_disabled_by_api = res.data.facebook_disabled_by_api; 1367 options.gdpr.analytics_disabled_by_api = res.data.analytics_disabled_by_api; 1368 options.gdpr.google_ads_disabled_by_api = res.data.google_ads_disabled_by_api; 1369 options.gdpr.pinterest_disabled_by_api = res.data.pinterest_disabled_by_api; 1370 options.gdpr.bing_disabled_by_api = res.data.bing_disabled_by_api; 1371 options.gdpr.reddit_disabled_by_api = res.data.reddit_disabled_by_api; 1372 1373 options.cookie.externalID_disabled_by_api = res.data.externalID_disabled_by_api; 1374 options.cookie.disabled_all_cookie = res.data.disabled_all_cookie; 1375 options.cookie.disabled_advanced_form_data_cookie = res.data.disabled_advanced_form_data_cookie; 1376 options.cookie.disabled_landing_page_cookie = res.data.disabled_landing_page_cookie; 1377 options.cookie.disabled_first_visit_cookie = res.data.disabled_first_visit_cookie; 1378 options.cookie.disabled_trafficsource_cookie = res.data.disabled_trafficsource_cookie; 1379 options.cookie.disabled_utmTerms_cookie = res.data.disabled_utmTerms_cookie; 1380 options.cookie.disabled_utmId_cookie = res.data.disabled_utmId_cookie; 1381 } 1382 1383 loadPixels(); 1384 1385 } 1386 }); 1387 1388 } else { 1389 loadPixels(); 1390 } 1391 1392 }, 1393 1394 consentGiven: function (pixel) { 1395 1396 /** 1397 * ConsentMagic 1398 */ 1399 if ( options.gdpr.consent_magic_integration_enabled && typeof CS_Data !== "undefined" ) { 1400 1401 let test_prefix = CS_Data.test_prefix; 1402 if ( 1403 ( ( typeof CS_Data.cs_google_consent_mode_enabled !== "undefined" && CS_Data.cs_google_consent_mode_enabled == 1 ) && ( pixel == 'analytics' || pixel == 'google_ads' ) ) 1404 || ( typeof CS_Data.cs_meta_ldu_mode !== "undefined" && CS_Data.cs_meta_ldu_mode && pixel == 'facebook' ) 1405 || ( typeof CS_Data.cs_reddit_ldu_mode !== "undefined" && CS_Data.cs_reddit_ldu_mode && pixel == 'reddit' ) 1406 || ( typeof CS_Data.cs_bing_consent_mode !== "undefined" && CS_Data.cs_bing_consent_mode.ad_storage.enabled && pixel == 'bing' ) 1407 ) { 1408 if ( CS_Data.cs_cache_enabled == 0 || ( CS_Data.cs_cache_enabled == 1 && window.CS_Cache && window.CS_Cache.check_status ) ) { 1409 return true; 1410 } else { 1411 return false;
1412 } 1413 } 1414 1415 if( pixel == 'facebook' && ( CS_Data.cs_script_cat.facebook == 0 || CS_Data.cs_script_cat.facebook == CS_Data.cs_necessary_cat_id ) ) { 1416 return true; 1417 } else if( pixel == 'bing' && ( CS_Data.cs_script_cat.bing == 0 || CS_Data.cs_script_cat.bing == CS_Data.cs_necessary_cat_id ) ) { 1418 return true; 1419 } else if( pixel == 'analytics' && ( CS_Data.cs_script_cat.analytics == 0 || CS_Data.cs_script_cat.analytics == CS_Data.cs_necessary_cat_id ) ) { 1420 return true; 1421 } else if( pixel == 'google_ads' && ( CS_Data.cs_script_cat.gads == 0 || CS_Data.cs_script_cat.gads == CS_Data.cs_necessary_cat_id ) ) { 1422 return true; 1423 } else if( pixel == 'pinterest' && ( CS_Data.cs_script_cat.pinterest == 0 || CS_Data.cs_script_cat.pinterest == CS_Data.cs_necessary_cat_id ) ) { 1424 return true; 1425 } else if( pixel == 'tiktok' && ( CS_Data.cs_script_cat.tiktok == 0 || CS_Data.cs_script_cat.tiktok == CS_Data.cs_necessary_cat_id ) ) { 1426 return true; 1427 } else if( pixel == 'reddit' && ( CS_Data.cs_script_cat?.reddit == 0 || CS_Data.cs_script_cat?.reddit == CS_Data.cs_necessary_cat_id ) ) { 1428 return true; 1429 } 1430 1431 let substring = "cs_enabled_cookie_term", 1432 theCookies = document.cookie.split( ';' ); 1433 1434 for ( let i = 1; i <= theCookies.length; i++ ) { 1435 if ( theCookies[ i - 1 ].indexOf( substring ) !== -1 ) { 1436 let categoryCookie = theCookies[ i - 1 ].replace( 'cs_enabled_cookie_term' + test_prefix + '_', '' ); 1437 categoryCookie = Number( categoryCookie.replace( /\D+/g, "" ) ); 1438 let cs_cookie_val = Cookies.get( 'cs_enabled_cookie_term' + test_prefix + '_' + categoryCookie ); 1439 1440 if ( categoryCookie === CS_Data.cs_script_cat.facebook && pixel == 'facebook' ) { 1441 return cs_cookie_val == 'yes'; 1442 } else if ( categoryCookie === CS_Data.cs_script_cat.bing && pixel == 'bing' ) { 1443 return cs_cookie_val == 'yes'; 1444 } else if ( categoryCookie === CS_Data.cs_script_cat.analytics && pixel == 'analytics' ) { 1445 return cs_cookie_val == 'yes'; 1446 } else if ( categoryCookie === CS_Data.cs_script_cat.gads && pixel == 'google_ads' ) { 1447 return cs_cookie_val == 'yes'; 1448 } else if ( categoryCookie === CS_Data.cs_script_cat.pinterest && pixel == 'pinterest' ) { 1449 return cs_cookie_val == 'yes'; 1450 } else if ( categoryCookie === CS_Data.cs_script_cat.tiktok && pixel == 'tiktok' ) { 1451 return cs_cookie_val == 'yes'; 1452 } else if ( categoryCookie === CS_Data.cs_script_cat?.reddit && pixel == 'reddit' ) { 1453 return cs_cookie_val == 'yes'; 1454 } 1455 } 1456 } 1457 1458 return false; 1459 } 1460 1461 /** 1462 * Real Cookie Banner 1463 */ 1464 if(options.gdpr.real_cookie_banner_integration_enabled) { 1465 var consentApi = window.consentApi; 1466 if (consentApi) { 1467 switch (pixel) { 1468 case "analytics": 1469 return consentApi.consentSync("http", "_ga", "*").cookieOptIn; 1470 case "facebook": 1471 return consentApi.consentSync("http", "_fbp", "*").cookieOptIn; 1472 case "pinterest": 1473 return consentApi.consentSync("http", "_pinterest_sess", ".pinterest.com").cookieOptIn; 1474 default: 1475 return true; 1476 } 1477 } 1478 } 1479 1480 /** 1481 * Cookiebot 1482 */ 1483 if (options.gdpr.cookiebot_integration_enabled && typeof Cookiebot !== 'undefined') { 1484 1485 var cookiebot_consent_category = options.gdpr['cookiebot_' + pixel + '_consent_category']; 1486 1487 if (options.gdpr[pixel + '_prior_consent_enabled']) { 1488 if (Cookiebot.consented === true || Cookiebot.consent[cookiebot_consent_category]) { 1489 return true; 1490 } 1491 } else { 1492 if (Cookiebot.consent[cookiebot_consent_category]) { 1493 return true; 1494 } 1495 } 1496 1497 return false;
1498 1499 } 1500 1501 /** 1502 * Cookie Notice 1503 */ 1504 if (options.gdpr.cookie_notice_integration_enabled && typeof cnArgs !== 'undefined') { 1505 1506 var cn_cookie = Cookies.get(cnArgs.cookieName); 1507 1508 if (options.gdpr[pixel + '_prior_consent_enabled']) { 1509 if (typeof cn_cookie === 'undefined' || cn_cookie === 'true') { 1510 return true; 1511 } 1512 } else { 1513 if (cn_cookie === 'true') { 1514 return true; 1515 } 1516 } 1517 1518 return false; 1519 1520 } 1521 1522 /** 1523 * Cookie Law Info 1524 */ 1525 if (options.gdpr.cookie_law_info_integration_enabled) { 1526 var cli_cookie = Cookies.get('cookieyes-consent') ?? Cookies.get('wt_consent') ?? Cookies.get('viewed_cookie_policy'); 1527 if (options.gdpr[pixel + '_prior_consent_enabled']) { 1528 if (typeof cli_cookie === 'undefined') return true; 1529 if ( 1530 cli_cookie && 1531 (cli_cookie === Cookies.get('cookieyes-consent') || cli_cookie === Cookies.get('wt_consent')) 1532 ) { 1533 if (getCookieYes('analytics') === 'yes') { 1534 return true; 1535 } 1536 } else if (cli_cookie && cli_cookie === Cookies.get('viewed_cookie_policy')) { 1537 if (Cookies.get('viewed_cookie_policy') === 'yes') { 1538 return true; 1539 } 1540 } 1541 } else { 1542 if ( 1543 cli_cookie && 1544 (cli_cookie === Cookies.get('cookieyes-consent') || cli_cookie === Cookies.get('wt_consent')) 1545 ) { 1546 if (getCookieYes('analytics') === 'yes') { 1547 return true; 1548 } 1549 } else if (cli_cookie && cli_cookie === Cookies.get('viewed_cookie_policy')) { 1550 if (Cookies.get('viewed_cookie_policy') === 'yes') { 1551 return true; 1552 } 1553 } 1554 } 1555 return false; 1556 } 1557 1558 return true; 1559 1560 }, 1561 1562 setupGdprCallbacks: function () { 1563 /** 1564 * ConsentMagic 1565 */ 1566 if (options.gdpr.consent_magic_integration_enabled && typeof CS_Data !== "undefined") { 1567 let test_prefix = CS_Data.test_prefix, 1568 cs_refresh_after_consent = false, 1569 substring = "cs_enabled_cookie_term"; 1570 1571 if (CS_Data.cs_refresh_after_consent == 1) { 1572 cs_refresh_after_consent = CS_Data.cs_refresh_after_consent; 1573 } 1574 1575 let consent_actions = function () { 1576 let theCookies = document.cookie.split( ';' ); 1577 1578 let consent = { 1579 facebook: true, 1580 ga: true, 1581 google_ads: true, 1582 tiktok: true, 1583 bing: true, 1584 pinterest: true, 1585 gtm: true, 1586 reddit: true, 1587 }; 1588 1589 for (let i = 1 ; i <= theCookies.length; i++) { 1590 if (theCookies[i-1].indexOf(substring) !== -1) { 1591 let categoryCookie = theCookies[i-1].replace('cs_enabled_cookie_term'+test_prefix+'_',''); 1592 categoryCookie = Number(categoryCookie.replace(/\D+/g,"")); 1593 let cs_cookie_val = Cookies.get('cs_enabled_cookie_term'+test_prefix+'_'+categoryCookie); 1594 if(cs_cookie_val == 'yes') { 1595 if ( ( categoryCookie === CS_Data.cs_script_cat.facebook ) || ( typeof CS_Data.cs_meta_ldu_mode !== "undefined" && CS_Data.cs_meta_ldu_mode ) ) { 1596 Facebook.loadPixel(); 1597 } 1598 1599 if ( categoryCookie === CS_Data.cs_script_cat.bing || ( typeof CS_Data.cs_bing_consent_mode !== "undefined" && CS_Data.cs_bing_consent_mode.ad_storage.enabled ) ) { 1600 Bing.loadPixel(); 1601 } 1602 1603 if (categoryCookie === CS_Data.cs_script_cat.analytics || (typeof CS_Data.cs_google_analytics_consent_mode !== "undefined" && CS_Data.cs_google_analytics_consent_mode == 1)
1603) { 1604 1605 Analytics.loadPixel(); 1606 } 1607 1608 if (categoryCookie === CS_Data.cs_script_cat.pinterest) { 1609 Pinterest.loadPixel(); 1610 } 1611 1612 if ( ( categoryCookie === CS_Data.cs_script_cat.reddit ) || ( typeof CS_Data.cs_reddit_ldu_mode !== "undefined" && CS_Data.cs_reddit_ldu_mode ) ) { 1613 Reddit.loadPixel(); 1614 } 1615 } else { 1616 if ( ( categoryCookie === CS_Data.cs_script_cat.facebook ) && ( typeof CS_Data.cs_meta_ldu_mode == "undefined" || !CS_Data.cs_meta_ldu_mode ) ) { 1617 Facebook.disable(); 1618 consent.facebook = false; 1619 } 1620 1621 if ( categoryCookie === CS_Data.cs_script_cat.bing && ( typeof CS_Data.cs_bing_consent_mode == "undefined" || !CS_Data.cs_bing_consent_mode.ad_storage.enabled ) ) { 1622 Bing.disable(); 1623 consent.bing = false; 1624 } 1625 if (categoryCookie === CS_Data.cs_script_cat.analytics && (typeof CS_Data.cs_google_analytics_consent_mode == "undefined" || CS_Data.cs_google_analytics_consent_mode == 0)) { 1626 Analytics.disable(); 1627 consent.ga = false; 1628 consent.gtm = false; 1629 } 1630 1631 if (categoryCookie === CS_Data.cs_script_cat.pinterest) { 1632 Pinterest.disable(); 1633 consent.pinterest = false; 1634 } 1635 1636 if ( ( categoryCookie === CS_Data.cs_script_cat.reddit ) && ( typeof CS_Data.cs_reddit_ldu_mode == "undefined" || !CS_Data.cs_reddit_ldu_mode ) ) { 1637 Reddit.disable(); 1638 consent.reddit = false; 1639 } 1640 } 1641 if (Cookies.get('cs_enabled_advanced_matching') == 'yes') { 1642 Facebook.loadPixel(); 1643 } 1644 } 1645 } 1646 Utils.setupGDPRData( consent ); 1647 } 1648 1649 if (!cs_refresh_after_consent) { 1650 consent_actions(); 1651 1652 $(document).on('click','.cs_action_btn',function(e) { 1653 e.preventDefault(); 1654 1655 let consent = { 1656 facebook: true, 1657 ga: true, 1658 bing: true, 1659 pinterest: true, 1660 gtm: true, 1661 reddit: true, 1662 }; 1663 1664 let elm = $(this), 1665 button_action = elm.attr('data-cs_action'); 1666 1667 if(button_action === 'allow_all') { 1668 Facebook.loadPixel(); 1669 Bing.loadPixel(); 1670 Analytics.loadPixel(); 1671 Pinterest.loadPixel(); 1672 Reddit.loadPixel(); 1673 1674 consent.facebook = true; 1675 consent.bing = true; 1676 consent.ga = true; 1677 consent.pinterest = true; 1678 consent.reddit = true; 1679 consent.gtm = true; 1680 1681 Utils.setupGDPRData( consent ); 1682 } else if ( button_action === 'disable_all' ) { 1683 if ( typeof CS_Data.cs_meta_ldu_mode == "undefined" || CS_Data.cs_meta_ldu_mode == 0 ) { 1684 Facebook.disable(); 1685 consent.facebook = false;
1686 } 1687 1688 if ( typeof CS_Data.cs_bing_consent_mode == "undefined" || CS_Data.cs_bing_consent_mode.ad_storage.enabled == 0 ) { 1689 Bing.disable(); 1690 consent.bing = false; 1691 } 1692 1693 if ( CS_Data.cs_google_analytics_consent_mode == 0 || typeof CS_Data.cs_google_analytics_consent_mode == "undefined" ) { 1694 Analytics.disable(); 1695 consent.ga = false; 1696 consent.gtm = false; 1697 } 1698 1699 if ( typeof CS_Data.cs_reddit_ldu_mode == "undefined" || CS_Data.cs_reddit_ldu_mode == 0 ) { 1700 Reddit.disable(); 1701 consent.reddit = false; 1702 } 1703 1704 Pinterest.disable(); 1705 consent.pinterest = false; 1706 Utils.setupGDPRData( consent ); 1707 } else if ( button_action === 'cs_confirm' ) { 1708 consent_actions(); 1709 } 1710 }); 1711 } 1712 } 1713 /** 1714 * Real Cookie Banner 1715 */ 1716 if(options.gdpr.real_cookie_banner_integration_enabled) { 1717 let consentApi = window.consentApi; 1718 if (consentApi) { 1719 consentApi.consent("http", "_ga", "*") 1720 .then(Analytics.loadPixel.bind(Analytics), Analytics.disable.bind(Analytics)); 1721 consentApi.consent("http", "_fbp", "*") 1722 .then(Facebook.loadPixel.bind(Facebook), Facebook.disable.bind(Facebook)); 1723 consentApi.consent("http", "_pinterest_sess", ".pinterest.com") 1724 .then(Pinterest.loadPixel.bind(Pinterest), Pinterest.disable.bind(Pinterest)); 1725 consentApi.consent("http", "_uetsid", "*") 1726 .then(Bing.loadPixel.bind(Bing), Bing.disable.bind(Bing)); 1727 1728 let consent = { 1729 facebook: true, 1730 ga: true, 1731 bing: true, 1732 pinterest: true, 1733 gtm: true, 1734 }; 1735 1736 if (!consentApi.consentSync("http", "_ga", "*").cookieOptIn) { 1737 consent.ga = false; 1738 consent.gtm = false; 1739 } 1740 if (!consentApi.consentSync("http", "_fbp", "*").cookieOptIn) { 1741 consent.facebook = false; 1742 } 1743 if (!consentApi.consentSync("http", "_pinterest_sess", ".pinterest.com").cookieOptIn) { 1744 consent.pinterest = false; 1745 } 1746 if (!consentApi.consentSync("http", "_uetsid", "*").cookieOptIn) { 1747 consent.bing = false; 1748 } 1749 Utils.setupGDPRData( consent ); 1750 } 1751 } 1752 /** 1753 * Cookiebot 1754 */ 1755 if (options.gdpr.cookiebot_integration_enabled && typeof Cookiebot !== 'undefined') { 1756 1757 window.addEventListener("CookiebotOnConsentReady", function() { 1758 1759 let consent = { 1760 facebook: true, 1761 ga: true, 1762 bing: true, 1763 pinterest: true, 1764 gtm: true, 1765 }; 1766 1767 Utils.manageCookies(); 1768 if (Cookiebot.consent.marketing) { 1769 Facebook.loadPixel(); 1770 Bing.loadPixel(); 1771 Pinterest.loadPixel(); 1772 1773 consent.facebook = true; 1774 consent.bing = true; 1775 consent.pinterest = true; 1776 } 1777 if (Cookiebot.consent.statistics) { 1778 Analytics.loadPixel(); 1779 1780 consent.ga = true; 1781 consent.gtm = true; 1782 } 1783 if (!Cookiebot.consent.marketing) { 1784 Facebook.disable(); 1785 Pinterest.disable(); 1786 Bing.disable(); 1787 1788 consent.facebook = false;
1789 consent.bing = false; 1790 consent.pinterest = false; 1791 } 1792 if (!Cookiebot.consent.statistics) { 1793 Analytics.disable(); 1794 1795 consent.ga = false; 1796 consent.gtm = false; 1797 } 1798 1799 Utils.setupGDPRData( consent ); 1800 }); 1801 1802 } 1803 1804 /** 1805 * Cookie Notice 1806 */ 1807 if (options.gdpr.cookie_notice_integration_enabled) { 1808 1809 $(document).onFirst('click', '.cn-set-cookie', function () { 1810 1811 let consent = {}; 1812 1813 if ($(this).data('cookie-set') === 'accept') { 1814 Facebook.loadPixel(); 1815 Analytics.loadPixel(); 1816 Pinterest.loadPixel(); 1817 Bing.loadPixel(); 1818 1819 consent = { 1820 facebook: true, 1821 ga: true, 1822 bing: true, 1823 pinterest: true, 1824 gtm: true, 1825 }; 1826 } else { 1827 Facebook.disable(); 1828 Analytics.disable(); 1829 Pinterest.disable(); 1830 Bing.disable(); 1831 1832 consent = { 1833 facebook: false, 1834 ga: false, 1835 bing: false, 1836 pinterest: false, 1837 gtm: false, 1838 }; 1839 } 1840 1841 Utils.setupGDPRData( consent ); 1842 }); 1843 1844 $(document).onFirst('click', '.cn-revoke-cookie', function () { 1845 Facebook.disable(); 1846 Analytics.disable(); 1847 Pinterest.disable(); 1848 Bing.disable(); 1849 1850 let consent = { 1851 facebook: false, 1852 ga: false, 1853 bing: false, 1854 pinterest: false, 1855 gtm: false, 1856 }; 1857 Utils.setupGDPRData( consent ); 1858 1859 }); 1860 1861 } 1862 1863 /** 1864 * Cookie Law Info 1865 */ 1866 if (options.gdpr.cookie_law_info_integration_enabled) { 1867 1868 $(document).onFirst('click', '#wt-cli-accept-all-btn,#cookie_action_close_header, .cky-btn-accept', function () { 1869 setTimeout(function (){ 1870 let cli_cookie = Cookies.get('cookieyes-consent') ?? Cookies.get('wt_consent') ?? Cookies.get('viewed_cookie_policy'); 1871 if (typeof cli_cookie !== 'undefined') { 1872 if (cli_cookie === Cookies.get('cookieyes-consent') || cli_cookie === Cookies.get('wt_consent')) { 1873 if (getCookieYes('analytics') === 'yes') { 1874 Utils.manageCookies(); 1875 } 1876 } else if (cli_cookie === Cookies.get('viewed_cookie_policy') && cli_cookie == 'yes') { 1877 Utils.manageCookies(); 1878 } 1879 } 1880 },1000) 1881 Facebook.loadPixel(); 1882 Analytics.loadPixel(); 1883 Pinterest.loadPixel(); 1884 Bing.loadPixel(); 1885 1886 let consent = { 1887 facebook: true, 1888 ga: true, 1889 bing: true, 1890 pinterest: true, 1891 gtm: true, 1892 }; 1893 Utils.setupGDPRData( consent ); 1894 }); 1895 1896 $(document).onFirst('click', '#cookie_action_close_header_reject, .cky-btn-reject', function () { 1897 Facebook.disable(); 1898 Analytics.disable(); 1899 Pinterest.disable(); 1900 Bing.disable(); 1901 1902 let consent = {
1903 facebook: false, 1904 ga: false, 1905 bing: false, 1906 pinterest: false, 1907 gtm: false, 1908 }; 1909 Utils.setupGDPRData( consent ); 1910 }); 1911 1912 } 1913 1914 }, 1915 1916 setupGDPRData: function ( consent ) { 1917 consent = window.btoa( JSON.stringify( consent ) ); 1918 Cookies.set( 'pys_consent', consent, { expires: 365, path: '/', domain: domain } ); 1919 }, 1920 1921 /** 1922 * DOWNLOAD DOCS 1923 */ 1924 1925 getLinkExtension: function (link) { 1926 1927 // Remove anchor, query string and everything before last slash 1928 link = link.substring(0, (link.indexOf("#") === -1) ? link.length : link.indexOf("#")); 1929 link = link.substring(0, (link.indexOf("?") === -1) ? link.length : link.indexOf("?")); 1930 link = link.substring(link.lastIndexOf("/") + 1, link.length); 1931 1932 // If there's a period left in the URL, then there's a extension 1933 if (link.length > 0 && link.indexOf('.') !== -1) { 1934 link = link.substring(link.indexOf(".") + 1); // Remove everything but what's after the first period 1935 return link; 1936 } else { 1937 return ""; 1938 } 1939 }, 1940 1941 getLinkFilename: function (link) { 1942 1943 // Remove anchor, query string and everything before last slash 1944 link = link.substring(0, (link.indexOf("#") === -1) ? link.length : link.indexOf("#")); 1945 link = link.substring(0, (link.indexOf("?") === -1) ? link.length : link.indexOf("?")); 1946 link = link.substring(link.lastIndexOf("/") + 1, link.length); 1947 1948 // If there's a period left in the URL, then there's a extension 1949 if (link.length > 0 && link.indexOf('.') !== -1) { 1950 return link; 1951 } else { 1952 return ""; 1953 } 1954 }, 1955 /** 1956 * Enrich 1957 */ 1958 isCheckoutPage: function () { 1959 return $('body').hasClass('woocommerce-checkout') || document.querySelector('.woocommerce-checkout') || 1960 $('body').hasClass('edd-checkout'); 1961 }, 1962 addCheckoutFields : function() { 1963 var utm = ""; 1964 var utms = getUTMs() 1965 1966 $.each(utmTerms, function (index, name) { 1967 if(index > 0) { 1968 utm+="|"; 1969 } 1970 utm+=name+":"+utms[name]; 1971 }); 1972 var utmIdList = ""; 1973 var utmsIds = getUTMId() 1974 $.each(utmId, function (index, name) { 1975 if(index > 0) { 1976 utmIdList+="|"; 1977 } 1978 utmIdList+=name+":"+utmsIds[name]; 1979 }); 1980 var utmIdListLast = ""; 1981 var utmsIdsLast = getUTMId(true) 1982 $.each(utmId, function (index, name) { 1983 if(index > 0) { 1984 utmIdListLast+="|"; 1985 } 1986 utmIdListLast+=name+":"+utmsIdsLast[name]; 1987 }); 1988 1989 1990 var utmLast = ""; 1991 var utmsLast = getUTMs(true) 1992 $.each(utmTerms, function (index, name) { 1993 if(index > 0) { 1994 utmLast+="|"; 1995 } 1996 utmLast+=name+":"+utmsLast[name]; 1997 }); 1998 1999 var dateTime = getDateTime(); 2000 var landing = getLandingPageValue(); 2001 var lastLanding = getLandingPageValue(); 2002 var trafic = getTrafficSourceValue(); 2003 var lastTrafic = getTrafficSourceValue(); 2004 2005 var $form = null; 2006 if($('body').hasClass('woocommerce-checkout')) { 2007 $form = $("form.woocommerce-checkout"); 2008 } else { 2009 $form = $("#edd_purchase_form"); 2010 } 2011 var inputs = {'pys_utm':utm, 2012 'pys_utm_id':utmIdList, 2013 'pys_browser_time':dateTime.join("|"), 2014 'pys_landing':landing, 2015 'pys_source':trafic, 2016 'pys_order_type': $(".wcf-optin-form").length > 0 ? "wcf-optin" : "normal", 2017 2018 'last_pys_landing':lastLanding, 2019 'last_pys_source':lastTrafic, 2020 'last_pys_utm':utmLast, 2021 'last_pys_utm_id':utmIdListLast, 2022 } 2023
2024 Object.keys(inputs).forEach(function(key,index) { 2025 $form.append("<input type='hidden' name='"+key+"' value='"+inputs[key]+"' /> "); 2026 }); 2027 2028 2029 }, 2030 getAdvancedFormData: function () { 2031 let dataStr = Cookies.get("pys_advanced_form_data"); 2032 if(dataStr === undefined) { 2033 return {'first_name':"",'last_name':"",'email':"",'phone':""}; 2034 } else { 2035 return JSON.parse(dataStr); 2036 } 2037 }, 2038 getFormFilledData: function ( event ) { 2039 // First, resolve static/dynamic parameters 2040 if (event.params && Object.keys(event.params).length > 0) { 2041 Object.entries(event.params).forEach(([key, value]) => { 2042 // Resolve parameter value (static or dynamic) 2043 const resolvedValue = resolveParamValue(value, key); 2044 if (resolvedValue !== null) { 2045 event.params[key] = resolvedValue; 2046 } 2047 else { 2048 delete event.params[key]; 2049 } 2050 }); 2051 } 2052 return event; 2053 } 2054 }; 2055 2056 }(options); 2057 2058 var Facebook = function (options) { 2059 2060 2061 var defaultEventTypes = [ 2062 'PageView', 2063 'ViewContent', 2064 'Search', 2065 'AddToCart', 2066 'AddToWishlist', 2067 'InitiateCheckout', 2068 'AddPaymentInfo', 2069 'Purchase', 2070 'Lead', 2071 2072 'Subscribe', 2073 'CustomizeProduct', 2074 'FindLocation', 2075 'StartTrial', 2076 'SubmitApplication', 2077 'Schedule', 2078 'Contact', 2079 'Donate' 2080 ]; 2081 2082 var initialized = false; 2083 var genereateFbp = function (){ 2084 return !Cookies.get('_fbp') ? 'fb.1.'+Date.now()+'.'+Math.floor(1000000000 + Math.random() * 9000000000) : Cookies.get('_fbp'); 2085 }; 2086 var genereateFbc = function (){ 2087 return getUrlParameter('fbclid') ? 'fb.1.'+Date.now()+'.'+getUrlParameter('fbclid') : '' 2088 }; 2089 // fire server side event gdpr plugin installed 2090 var isApiDisabled = options.gdpr.all_disabled_by_api || 2091 options.gdpr.facebook_disabled_by_api || 2092 options.gdpr.cookiebot_integration_enabled || 2093 options.gdpr.consent_magic_integration_enabled || 2094 options.gdpr.cookie_notice_integration_enabled || 2095 options.gdpr.cookie_law_info_integration_enabled; 2096 2097 /** 2098 * 2099 * @param allData 2100 * @param params 2101 * @returns {string | null} 2102 */ 2103 function sendFbServerEvent(allData,name,params) { 2104 let eventId = null; 2105 if(options.facebook.serverApiEnabled) { 2106 2107 if(allData.e_id === "woo_remove_from_cart") {// server event will sended from hook 2108 Facebook.updateEventId(allData.name); 2109 allData.eventID = Facebook.getEventId(allData.name); 2110 } else { 2111 // send event from server if they was bloc by gdpr or need send with delay 2112 allData.eventID = Utils.generateUniqueId(allData); 2113 2114 if(Cookies.get('_fbp')){ 2115 params._fbp = Cookies.get('_fbp'); 2116 } 2117 if(Cookies.get('_fbc')){ 2118 params._fbc = Cookies.get('_fbc'); 2119 } 2120 2121 if( options.ajaxForServerEvent || isApiDisabled ){ 2122 var json = { 2123 action: 'pys_api_event', 2124 pixel: 'facebook', 2125 event: name, 2126 data:params, 2127 ids:options.facebook.pixelIds, 2128 eventID:allData.eventID, 2129 url:window.location.href, 2130 ajax_event:options.ajax_event 2131 }; 2132 if(allData.hasOwnProperty('woo_order')) { 2133 json['woo_order'] = allData.woo_order; 2134 } 2135 if(allData.hasOwnProperty('edd_order')) { 2136 json['edd_order'] = allData.edd_order; 2137 } 2138 if (pageReferrer) { 2139 json.referrer_url = pageReferrer; 2140 } 2141 2142 if (allData.e_id === "automatic_event_internal_link" || allData.e_id === "automatic_event_outbound_link") { 2143 setTimeout(() => Utils.sendServerAjaxRequest(options.ajaxUrl, json), 500); 2144 } else if (allData.type != 'static') { 2145 Utils.sendServerAjaxRequest(options.ajaxUrl, json); 2146 } 2147 2148 if ( ( allData.type == 'static' && options.ajaxForServerStaticEvent ) || ( allData.hasOwnProperty( 'ajaxFire' ) && allData.ajaxFire ) ) { 2149 Utils.sendServerAjaxRequest( options.ajaxUrl, json ); 2150 } 2151 } 2152 } 2153 delete params._fbp; 2154 delete params._fbc; 2155 eventId = allData.eventID 2156 } 2157 return eventId; 2158 } 2159 2160 function fireEvent(name, allData) { 2161 2162 if(typeof window.pys_event_data_filter === "function" && window.pys_disable_event_filter(name,'facebook')) { 2163 return; 2164 } 2165 2166 var actionType = defaultEventTypes.includes(name) ? 'track' : 'trackCustom'; 2167 var data = allData.params; 2168 var params = {}; 2169 var arg = {}; 2170 Utils.copyProperties(data, params); 2171 let eventId = sendFbServerEvent(allData,name,params) 2172 2173 2174 if("hCR" === name) { 2175 return; 2176 } 2177 2178 if (options.debug) { 2179 console.log('[Facebook] ' + name, params,"eventID",eventId); 2180 } 2181 2182 if(eventId != null) { 2183 arg.eventID = eventId; 2184 } 2185 2186 fbq(actionType, name, params, arg); 2187 2188 } 2189 2190 /** 2191 * Public API 2192 */ 2193 return { 2194 tag: function() { 2195 return "facebook"; 2196 }, 2197 isEnabled: function () { 2198 return options.hasOwnProperty('facebook'); 2199 }, 2200 2201 disable: function () { 2202 initialized = false;
2203 }, 2204 advancedMatching: function () { 2205 if(options.facebook.advancedMatchingEnabled) { 2206 let advancedMatchingForm = Utils.getAdvancedFormData(); 2207 let advancedMatching = {}; 2208 if(Object.keys(options.facebook.advancedMatching).length > 0) { 2209 advancedMatching = options.facebook.advancedMatching; 2210 } 2211 2212 if(!advancedMatching.hasOwnProperty("em") 2213 && advancedMatchingForm.hasOwnProperty("email") && advancedMatchingForm["email"].length > 0) { 2214 advancedMatching["em"] = advancedMatchingForm["email"]; 2215 } 2216 if(!advancedMatching.hasOwnProperty("ph") 2217 && advancedMatchingForm.hasOwnProperty("phone") && advancedMatchingForm["phone"].length > 0) { 2218 advancedMatching["ph"] = advancedMatchingForm["phone"]; 2219 } 2220 if(!advancedMatching.hasOwnProperty("fn") 2221 && advancedMatchingForm.hasOwnProperty("first_name") && advancedMatchingForm["first_name"].length > 0) { 2222 advancedMatching["fn"] = advancedMatchingForm["first_name"]; 2223 } 2224 if(!advancedMatching.hasOwnProperty("ln") 2225 && advancedMatchingForm.hasOwnProperty("last_name") && advancedMatchingForm["last_name"].length > 0) { 2226 advancedMatching["ln"] = advancedMatchingForm["last_name"]; 2227 } 2228 if(!advancedMatching.hasOwnProperty("external_id")){ 2229 if (Cookies.get('pbid') || (options.hasOwnProperty('pbid') && options.pbid)) { 2230 advancedMatching["external_id"] = Cookies.get('pbid') ? Cookies.get('pbid') : options.pbid; 2231 } 2232 } 2233 else if(advancedMatching.external_id != Cookies.get('pbid')) 2234 { 2235 advancedMatching["external_id"] = Cookies.get('pbid') ? Cookies.get('pbid') : advancedMatching.external_id; 2236 } 2237 if(Object.keys(advancedMatching).length > 0) { 2238 return advancedMatching; 2239 } 2240 } 2241 return false 2242 }, 2243 /** 2244 * Load pixel's JS 2245 */ 2246 loadPixel: function () { 2247 2248 if (initialized || !this.isEnabled() || !Utils.consentGiven('facebook')) { 2249 return; 2250 } 2251 2252 !function (f, b, e, v, n, t, s) { 2253 if (f.fbq) return; 2254 n = f.fbq = function () { 2255 n.callMethod ? 2256 n.callMethod.apply(n, arguments) : n.queue.push(arguments) 2257 }; 2258 if (!f._fbq) f._fbq = n; 2259 n.push = n; 2260 n.loaded = !0; 2261 n.version = '2.0'; 2262 n.agent = 'dvpixelyoursite'; 2263 n.queue = []; 2264 t = b.createElement(e); 2265 t.async = !0; 2266 t.src = v; 2267 s = b.getElementsByTagName(e)[0]; 2268 s.parentNode.insertBefore(t, s) 2269 }(window, 2270 document, 'script', 'https://connect.facebook.net/en_US/fbevents.js'); 2271 2272 let expires = parseInt(options.cookie_duration); 2273 if(!Cookies.get('_fbp')) { 2274 Cookies.set('_fbp',genereateFbp(), { expires: expires,path: '/',domain: domain }); 2275 } 2276 2277 if(getUrlParameter('fbclid')) { 2278 Cookies.set('_fbc',genereateFbc(), { expires: expires,path: '/',domain: domain }); 2279 } 2280 2281 // Now that Facebook consent is confirmed, mirror the session 2282 // entry referrer (if any) into the session cookie so PHP can 2283 // use it as a fallback for orphan server-only events. 2284 getOrInitSessionEntryReferrer(true); 2285 2286 // Refresh the per-page event referrer cookie so checkout 2287 // hooks can snapshot the buyer's prior page. 2288 writeEventReferrerCookie(); 2289 2290 // initialize pixel 2291 options.facebook.pixelIds.forEach(function (pixelId) { 2292 if (options.facebook.removeMetadata) { 2293 fbq('set', 'autoConfig', false, pixelId); 2294 } 2295 let advancedMatching = Facebook.advancedMatching(); 2296 2297 if ( +options.facebook.meta_ldu === 1 ) { 2298 fbq( 'dataProcessingOptions', [ 'LDU' ], 0, 0 ); 2299 } 2300 2301 if (options.gdpr.consent_magic_integration_enabled && typeof CS_Data !== "undefined") { 2302 if(!advancedMatching) { 2303 fbq('init', pixelId); 2304 } else { 2305 var test_prefix = CS_Data.test_prefix; 2306 var cs_advanced_matching = Cookies.get('cs_enabled_advanced_matching'+test_prefix); 2307 if (jQuery('#cs_enabled_advanced_matching'+test_prefix).length > 0) { 2308 if (cs_advanced_matching == 'yes') { 2309 fbq('init', pixelId, advancedMatching); 2310 } else { 2311 fbq('init', pixelId); 2312 } 2313 } else { 2314 fbq('init', pixelId, advancedMatching); 2315 } 2316 } 2317 } else { 2318 if(!advancedMatching) { 2319 fbq('init', pixelId); 2320 } else { 2321 fbq('init', pixelId, advancedMatching); 2322 } 2323 } 2324 }); 2325 2326 initialized = true; 2327 2328 Utils.fireStaticEvents('facebook'); 2329 2330 }, 2331 2332 fireEvent: function (name, data) { 2333 2334 if (!initialized || !this.isEnabled()) { 2335 return false;
2336 } 2337 2338 data.delay = data.delay || 0; 2339 data.params = data.params || {}; 2340 2341 if (data.delay === 0) { 2342 2343 fireEvent(name, data); 2344 2345 } else { 2346 2347 setTimeout(function (name, params) { 2348 fireEvent(name, params); 2349 }, data.delay * 1000, name, data); 2350 2351 } 2352 2353 return true; 2354 2355 }, 2356 2357 onCommentEvent: function (event) { 2358 this.fireEvent(event.name, event); 2359 }, 2360 2361 onDownloadEvent: function (event) { 2362 this.fireEvent(event.name, event); 2363 }, 2364 2365 onFormEvent: function (event) { 2366 2367 this.fireEvent(event.name, event); 2368 2369 }, 2370 2371 onWooAddToCartOnButtonEvent: function (product_id) { 2372 2373 if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag())) 2374 return; 2375 var event = options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()]; 2376 window.pysWooProductData = window.pysWooProductData || []; 2377 if (window.pysWooProductData.hasOwnProperty(product_id)) { 2378 if (window.pysWooProductData[product_id].hasOwnProperty('facebook')) { 2379 event = Utils.copyProperties(event, {}) 2380 Utils.copyProperties(window.pysWooProductData[product_id]['facebook'].params, event.params) 2381 this.fireEvent(event.name, event); 2382 } 2383 } 2384 }, 2385 2386 onWooAddToCartOnSingleEvent: function (product_id, qty, product_type, $form) { 2387 2388 window.pysWooProductData = window.pysWooProductData || []; 2389 if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag())) 2390 return; 2391 var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()]); 2392 2393 if (product_type === Utils.PRODUCT_VARIABLE && !options.facebook.wooVariableAsSimple) { 2394 product_id = parseInt($form.find('input[name="variation_id"]').val()); 2395 } 2396 2397 if (window.pysWooProductData.hasOwnProperty(product_id)) { 2398 if (window.pysWooProductData[product_id].hasOwnProperty('facebook')) { 2399 2400 2401 Utils.copyProperties(window.pysWooProductData[product_id]['facebook'].params, event.params); 2402 2403 var groupValue = 0; 2404 if(product_type === Utils.PRODUCT_GROUPED ) { 2405 $form.find(".woocommerce-grouped-product-list .qty").each(function(index){ 2406 var childId = $(this).attr('name').replaceAll("quantity[","").replaceAll("]",""); 2407 var quantity = parseInt($(this).val()); 2408 if(isNaN(quantity)) { 2409 quantity = 0; 2410 } 2411 var childItem = window.pysWooProductData[product_id]['facebook'].grouped[childId]; 2412 2413 if(quantity == 0) { 2414 event.params.content_ids.forEach(function(el,index,array) { 2415 if(el == childItem.content_id) { 2416 array.splice(index, 1); 2417 } 2418 }); 2419 } 2420 2421 if(event.params.hasOwnProperty('contents')) { 2422 event.params.contents.forEach(function(el,index,array) { 2423 if(el.id == childItem.content_id) { 2424 if(quantity > 0){ 2425 el.quantity = quantity; 2426 } else { 2427 array.splice(index, 1); 2428 } 2429 } 2430 }); 2431 } 2432 2433 2434 groupValue += childItem.price * quantity; 2435 }); 2436 if(groupValue == 0) return;
2436 // skip if no items selected 2437 } 2438 2439 // maybe customize value option 2440 if (options.woo.addToCartOnButtonValueEnabled && options.woo.addToCartOnButtonValueOption !== 'global') { 2441 2442 if(product_type === Utils.PRODUCT_GROUPED) { 2443 event.params.value = groupValue; 2444 } else if(product_type === Utils.PRODUCT_BUNDLE) { 2445 var data = $(".bundle_form .bundle_data").data("bundle_form_data"); 2446 var items_sum = getBundlePriceOnSingleProduct(data); 2447 event.params.value = (parseInt(data.base_price) + items_sum )* qty; 2448 } else { 2449 event.params.value = event.params.value * qty; 2450 } 2451 } 2452 2453 // only when non Facebook for WooCommerce logic used 2454 if (event.params.hasOwnProperty('contents') && product_type !== Utils.PRODUCT_GROUPED) { 2455 event.params.contents[0].quantity = qty; 2456 } 2457 2458 this.fireEvent(event.name, event); 2459 2460 } 2461 } 2462 }, 2463 2464 onWooRemoveFromCartEvent: function (event) { 2465 this.fireEvent(event.name, event); 2466 }, 2467 2468 onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) { 2469 2470 if(!options.dynamicEvents.edd_add_to_cart_on_button_click.hasOwnProperty(this.tag())) 2471 return; 2472 var event = Utils.clone(options.dynamicEvents.edd_add_to_cart_on_button_click[this.tag()]); 2473 2474 if (window.pysEddProductData && window.pysEddProductData.hasOwnProperty(download_id)) { 2475 2476 var index; 2477 2478 if (price_index) { 2479 index = download_id + '_' + price_index; 2480 } else { 2481 index = download_id; 2482 } 2483 2484 if (window.pysEddProductData[download_id].hasOwnProperty(index)) { 2485 if (window.pysEddProductData[download_id][index].hasOwnProperty('facebook')) { 2486 2487 2488 Utils.copyProperties(window.pysEddProductData[download_id][index]['facebook']["params"], event.params) 2489 2490 // maybe customize value option 2491 if (options.edd.addToCartOnButtonValueEnabled && options.edd.addToCartOnButtonValueOption !== 'global') { 2492 event.params.value = event.params.value * qty; 2493 } 2494 2495 // update contents qty param 2496 var contents = event.params.contents; 2497 contents[0].quantity = qty; 2498 event.params.contents = contents; 2499 2500 this.fireEvent(event.name,event); 2501 2502 } 2503 } 2504 2505 } 2506 2507 }, 2508 2509 onEddRemoveFromCartEvent: function (event) { 2510 this.fireEvent(event.name, event); 2511 }, 2512 onPageScroll: function (event) { 2513 this.fireEvent(event.name, event); 2514 }, 2515 onTime: function (event) { 2516 this.fireEvent(event.name, event); 2517 }, 2518 initEventIdCookies: function (key) { 2519 var ids = {}; 2520 ids[key] = pys_generate_token(36) 2521 Cookies.set('pys_fb_event_id', JSON.stringify(ids)); 2522 }, 2523 updateEventId:function(key) { 2524 var cooData = Cookies.get("pys_fb_event_id") 2525 if(cooData === undefined) { 2526 this.initEventIdCookies(key); 2527 } else { 2528 var data = JSON.parse(cooData); 2529 data[key] = pys_generate_token(36); 2530 Cookies.set('pys_fb_event_id', JSON.stringify(data) ); 2531 } 2532 }, 2533 2534 getEventId:function (key) { 2535 var data = Cookies.get("pys_fb_event_id"); 2536 if(data === undefined) {
2537 this.initEventIdCookies(key); 2538 data = Cookies.get("pys_fb_event_id"); 2539 } 2540 return JSON.parse(data)[key]; 2541 }, 2542 2543 sendFacebookRestAPIRequest: function(allData, name, params) { 2544 if (typeof window.pysFacebookRest === 'undefined' || !window.pysFacebookRest.restApiUrl) { 2545 return; 2546 } 2547 2548 const restApiData = { 2549 event: name, 2550 data: JSON.stringify(params), 2551 ids: allData.pixelIds || options.facebook.pixelIds, 2552 eventID: allData.eventID, 2553 woo_order: allData.woo_order || 0, 2554 edd_order: allData.edd_order || 0 2555 }; 2556 2557 if (pageReferrer) { 2558 restApiData.referrer_url = pageReferrer; 2559 } 2560 2561 // Variant A: send the actual page URL where the event happened 2562 // so the server sets event_source_url to this page, not the 2563 // REST endpoint. PHP applies enable_remove_source_url_params. 2564 restApiData.event_source_url = window.location.href; 2565 2566 // Try sendBeacon first 2567 if (navigator.sendBeacon) { 2568 const formData = new FormData(); 2569 Object.keys(restApiData).forEach(key => { 2570 if (Array.isArray(restApiData[key])) { 2571 restApiData[key].forEach(value => { 2572 formData.append(key + '[]', value); 2573 }); 2574 } else { 2575 formData.append(key, restApiData[key]); 2576 } 2577 }); 2578 2579 if (navigator.sendBeacon(window.pysFacebookRest.restApiUrl, formData)) { 2580 return; 2581 } 2582 } 2583 2584 // Fallback to fetch 2585 fetch(window.pysFacebookRest.restApiUrl, { 2586 method: 'POST', 2587 headers: { 2588 'Content-Type': 'application/x-www-form-urlencoded', 2589 }, 2590 body: new URLSearchParams(restApiData) 2591 }).catch(() => { 2592 // Fallback to AJAX if fetch fails 2593 this.sendAjaxFallback(allData, name, params); 2594 }); 2595 }, 2596 2597 sendAjaxFallback: function(allData, name, params) { 2598 var json = { 2599 action: 'pys_api_event', 2600 pixel: 'facebook', 2601 event: name, 2602 data: params, 2603 ids: allData.pixelIds || options.facebook.pixelIds, 2604 eventID: allData.eventID, 2605 url: window.location.href, 2606 ajax_event: options.ajax_event 2607 }; 2608 if (allData.hasOwnProperty('woo_order')) { 2609 json['woo_order'] = allData.woo_order; 2610 } 2611 if (allData.hasOwnProperty('edd_order')) { 2612 json['edd_order'] = allData.edd_order; 2613 } 2614 if (pageReferrer) { 2615 json.referrer_url = pageReferrer; 2616 } 2617 2618 Utils.sendServerAjaxRequest(options.ajaxUrl, json); 2619 }, 2620 }; 2621 2622 }(options); 2623 2624 var Analytics = function (options) { 2625 2626 var initialized = false; 2627 2628 /** 2629 * Fires event 2630 * 2631 * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/sending-data 2632 * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/events 2633 * @link: https://developers.google.com/gtagjs/reference/event 2634 * @link: https://developers.google.com/gtagjs/reference/parameter 2635 * 2636 * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/custom-dims-mets 2637 * 2638 * @param name 2639 * @param data 2640 */ 2641 function fireEvent(name, data) { 2642 2643 if(typeof window.pys_event_data_filter === "function" && window.pys_disable_event_filter(name,'ga')) { 2644 return; 2645 } 2646
2647 var eventParams = Utils.copyProperties(data, {}); 2648 var _fireEvent = function (tracking_id,name,params) { 2649 2650 params['send_to'] = tracking_id; 2651 2652 if (options.debug) { 2653 console.log('[Google Analytics #' + tracking_id + '] ' + name, params); 2654 } 2655 2656 gtag('event', name, params); 2657 2658 }; 2659 options.ga.trackingIds.forEach(function (tracking_id) { 2660 var copyParams = Utils.copyProperties(eventParams, {}); // copy params because mapParamsTov4 can modify it 2661 var params = mapParamsTov4(tracking_id,name,copyParams) 2662 _fireEvent(tracking_id,name,params); 2663 }); 2664 2665 } 2666 function mapParamsTov4(tag,name,param) { 2667 //GA4 automatically collects a number of parameters for all events 2668 delete param.landing_page; 2669 // end 2670 if(isv4(tag)) { 2671 delete param.traffic_source; 2672 delete param.event_category; 2673 delete param.event_label; 2674 delete param.ecomm_prodid; 2675 delete param.ecomm_pagetype; 2676 delete param.ecomm_totalvalue; 2677 if(name === 'search') { 2678 param['search'] = param.search_term; 2679 delete param.search_term; 2680 delete param.dynx_itemid; 2681 delete param.dynx_pagetype; 2682 delete param.dynx_totalvalue; 2683 } 2684 } 2685 return param; 2686 } 2687 2688 function isv4(tag) { 2689 return tag.indexOf('G') === 0; 2690 } 2691 2692 /** 2693 * Public API 2694 */ 2695 return { 2696 tag: function() { 2697 return "ga"; 2698 }, 2699 isEnabled: function () { 2700 return options.hasOwnProperty('ga'); 2701 }, 2702 2703 disable: function () { 2704 initialized = false; 2705 }, 2706 2707 loadPixel: function () { 2708 2709 if (initialized || !this.isEnabled() || !Utils.consentGiven('analytics')) { 2710 return; 2711 } 2712 2713 Utils.loadGoogleTag(options.ga.trackingIds[0]); 2714 var config = {}; 2715 // Cross-Domain tracking 2716 if (options.ga.crossDomainEnabled) { 2717 config.linker = { 2718 accept_incoming: options.ga.crossDomainAcceptIncoming, 2719 domains: options.ga.crossDomainDomains 2720 }; 2721 } 2722 var ids = options.ga.trackingIds; 2723 // configure tracking ids 2724 ids.forEach(function (trackingId,index) { 2725 var obj = options.ga.isDebugEnabled; 2726 var searchValue = "index_"+index; 2727 var config_for_tag = Object.assign({}, options.config); 2728 config_for_tag.debug_mode = false;
2729 config_for_tag.send_page_view = !options.ga.custom_page_view_event; 2730 for (var key in obj) { 2731 if (obj.hasOwnProperty(key) && obj[key] === searchValue) { 2732 config_for_tag.debug_mode = true; 2733 break; 2734 } 2735 } 2736 if(!config_for_tag.debug_mode) 2737 { 2738 delete config_for_tag.debug_mode; 2739 } 2740 if(isv4(trackingId)) { 2741 if(options.ga.disableAdvertisingFeatures) { 2742 config_for_tag.allow_google_signals = false 2743 } 2744 if(options.ga.disableAdvertisingPersonalization) { 2745 config_for_tag.allow_ad_personalization_signals = false 2746 } 2747 } 2748 if(options.ga.hasOwnProperty('additionalConfig')){ 2749 if(options.ga.additionalConfig.hasOwnProperty(trackingId) && options.ga.additionalConfig[trackingId]){ 2750 config_for_tag.first_party_collection = options.ga.additionalConfig[trackingId].first_party_collection; 2751 } 2752 2753 } 2754 if(options.ga.hasOwnProperty('serverContainerUrls')){ 2755 if(options.ga.serverContainerUrls.hasOwnProperty(trackingId) && options.ga.serverContainerUrls[trackingId].enable_server_container != false){ 2756 if(options.ga.serverContainerUrls[trackingId].server_container_url != ''){ 2757 config_for_tag.server_container_url = options.ga.serverContainerUrls[trackingId].server_container_url; 2758 } 2759 if(options.ga.serverContainerUrls[trackingId].transport_url != ''){ 2760 config_for_tag.transport_url = options.ga.serverContainerUrls[trackingId].transport_url; 2761 } 2762 } 2763 } 2764 if (options.gdpr.cookiebot_integration_enabled && typeof Cookiebot !== 'undefined') { 2765 2766 var cookiebot_consent_category = options.gdpr['cookiebot_analytics_consent_category']; 2767 if (options.gdpr['analytics_prior_consent_enabled']) { 2768 if (Cookiebot.consented === true && Cookiebot.consent[cookiebot_consent_category]) { 2769 gtag('config', trackingId, config_for_tag); 2770 } 2771 } else { 2772 if (Cookiebot.consent[cookiebot_consent_category]) { 2773 gtag('config', trackingId, config_for_tag); 2774 } 2775 } 2776 } 2777 else 2778 { 2779 gtag('config', trackingId, config_for_tag); 2780 } 2781 }); 2782 2783 initialized = true; 2784 2785 Utils.fireStaticEvents('ga'); 2786 2787 }, 2788 2789 fireEvent: function (name, data) { 2790 2791 if (!initialized || !this.isEnabled()) { 2792 return false; 2793 } 2794 2795 data.delay = data.delay || 0; 2796 data.params = data.params || {}; 2797 data.params.eventID = Utils.generateUniqueId(data); 2798 if (data.delay === 0) { 2799 2800 fireEvent(name, data.params); 2801 2802 } else { 2803 2804 setTimeout(function (name, params) { 2805 fireEvent(name, params); 2806 }, data.delay * 1000, name, data.params); 2807 2808 } 2809 2810 return true; 2811 2812 }, 2813 2814 onCommentEvent: function (event) { 2815 this.fireEvent(event.name, event); 2816 }, 2817 2818 onDownloadEvent: function (event) { 2819 this.fireEvent(event.name, event); 2820 }, 2821 2822 onFormEvent: function (event) { 2823 this.fireEvent(event.name, event); 2824 }, 2825 2826 onWooAddToCartOnButtonEvent: function (product_id) { 2827 2828 if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag())) 2829 return; 2830 var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()]); 2831 2832 if (window.pysWooProductData.hasOwnProperty(product_id)) { 2833 if (window.pysWooProductData[product_id].hasOwnProperty('ga')) { 2834 Utils.copyProperties(window.pysWooProductData[product_id]['ga'].params, event.params) 2835 this.fireEvent(event.name, event); 2836 } 2837 } 2838 2839 2840 }, 2841 2842 onWooAddToCartOnSingleEvent: function (product_id, qty, product_type, $form) { 2843 2844 window.pysWooProductData = window.pysWooProductData || []; 2845 2846 if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag())) 2847 return; 2848 var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()]); 2849 2850 if (product_type === Utils.PRODUCT_VARIABLE && !options.ga.wooVariableAsSimple) { 2851 product_id = parseInt($form.find('input[name="variation_id"]').val()); 2852 } 2853 2854 if (window.pysWooProductData.hasOwnProperty(product_id)) { 2855 if (window.pysWooProductData[product_id].hasOwnProperty('ga')) { 2856 2857 Utils.copyProperties(window.pysWooProductData[product_id]['ga'].params, event.params); 2858 if(product_type === Utils.PRODUCT_GROUPED ) { 2859 var groupValue = 0; 2860 $form.find(".woocommerce-grouped-product-list .qty").each(function(index){ 2861 var childId = $(this).attr('name').replaceAll("quantity[","").replaceAll("]",""); 2862 var quantity = parseInt($(this).val()); 2863 if(isNaN(quantity)) { 2864 quantity = 0; 2865 } 2866 var childItem = window.pysWooProductData[product_id]['ga'].grouped[childId]; 2867 // update quantity
2868 event.params.items.forEach(function(el,index,array) { 2869 if(el.id == childItem.content_id) { 2870 if(quantity > 0){ 2871 el.quantity = quantity; 2872 } else { 2873 array.splice(index, 1); 2874 } 2875 } 2876 }); 2877 groupValue += childItem.price * quantity; 2878 }); 2879 if(options.woo.addToCartOnButtonValueEnabled && 2880 options.woo.addToCartOnButtonValueOption !== 'global' && 2881 event.params.hasOwnProperty('ecomm_totalvalue')) { 2882 event.params.ecomm_totalvalue = groupValue; 2883 } 2884 2885 if(groupValue == 0) return; // skip if no items selected 2886 } else { 2887 // update items qty param 2888 event.params.items[0].quantity = qty; 2889 } 2890 2891 // maybe customize value option 2892 if (options.woo.addToCartOnButtonValueEnabled && 2893 options.woo.addToCartOnButtonValueOption !== 'global' && 2894 product_type !== Utils.PRODUCT_GROUPED) 2895 { 2896 if(event.params.hasOwnProperty('ecomm_totalvalue')) { 2897 event.params.ecomm_totalvalue = event.params.items[0].price * qty; 2898 } 2899 2900 } 2901 2902 2903 this.fireEvent(event.name, event); 2904 } 2905 } 2906 2907 }, 2908 2909 onWooRemoveFromCartEvent: function (event) { 2910 2911 this.fireEvent(event.name, event); 2912 2913 }, 2914 2915 onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) { 2916 2917 if(!options.dynamicEvents.edd_add_to_cart_on_button_click.hasOwnProperty(this.tag())) 2918 return; 2919 var event = Utils.clone(options.dynamicEvents.edd_add_to_cart_on_button_click[this.tag()]); 2920 2921 2922 if (window.pysEddProductData && window.pysEddProductData.hasOwnProperty(download_id)) { 2923 2924 var index; 2925 2926 if (price_index) { 2927 index = download_id + '_' + price_index; 2928 } else { 2929 index = download_id; 2930 } 2931 2932 if (window.pysEddProductData[download_id].hasOwnProperty(index)) { 2933 if (window.pysEddProductData[download_id][index].hasOwnProperty('ga')) { 2934 2935 Utils.copyProperties(window.pysEddProductData[download_id][index]['ga'].params, event.params); 2936 2937 // update items qty param 2938 event.params.items[0].quantity = qty; 2939 2940 this.fireEvent(event.name,event); 2941 2942 } 2943 } 2944 2945 } 2946 2947 }, 2948 2949 onEddRemoveFromCartEvent: function (event) { 2950 this.fireEvent(event.name, event); 2951 }, 2952 onPageScroll: function (event) { 2953 this.fireEvent(event.name, event); 2954 }, 2955 onTime: function (event) { 2956 this.fireEvent(event.name, event); 2957 }, 2958 2959 }; 2960 2961 }(options); 2962 2963 var GTM = function (options) { 2964 var initialized = false; 2965 2966 var datalayer_name = 'dataLayer'; 2967 /* 2968 * @param name 2969 * @param data 2970 */ 2971 function fireEvent(name, event) { 2972 if(typeof window.pys_event_data_filter === "function" && window.pys_disable_event_filter(name,'gtm')) { 2973 return; 2974 } 2975 2976 2977 var eventParams = event.params; 2978 var data = event.params; 2979 var valuesArray = Object.values(event.trackingIds); 2980 var ids = valuesArray;
2981 Utils.copyProperties(Utils.getRequestParams(), eventParams); 2982 var _fireEvent = function (tracking_id,name,params, event=null) { 2983 var eventData = {}; 2984 var ContainerCodeHasTag = !options.gtm.gtm_just_data_layer && tracking_id.length > 0; 2985 if(ContainerCodeHasTag) { 2986 params['send_to'] = tracking_id; 2987 } 2988 else if(!options.gtm.gtm_just_data_layer){ 2989 return 2990 } 2991 2992 if (params.hasOwnProperty('ecommerce')) { 2993 eventData.ecommerce = params.ecommerce; 2994 delete params.ecommerce; 2995 } 2996 2997 var automatedParams = { ...params }; 2998 [params['manualName'], 'manualName', 'triggerType'].forEach(key => delete automatedParams[key]); 2999 if(event && (!event.hasOwnProperty('hasAutoParam') || (event.hasOwnProperty('hasAutoParam') && event.hasAutoParam))) { 3000 eventData.automatedParameters = automatedParams; 3001 } 3002 3003// Move custom parameters to eventData 3004 3005 if (params.hasOwnProperty(params['manualName'])) { 3006 eventData[params['manualName']] = params[params['manualName']]; 3007 delete params[params['manualName']]; 3008 } 3009 3010 ['manualName','triggerType'].forEach(key => { 3011 if (params.hasOwnProperty(key)) { 3012 eventData[key] = params[key]; 3013 delete params[key]; 3014 } 3015 }); 3016 3017 eventData.manualDataLayer = options.gtm.gtm_dataLayer_name ?? 'dataLayer'; 3018 3019 eventData.event = name; 3020 3021 if (options.debug) { 3022 if (ContainerCodeHasTag){ 3023 console.log('[Google GTM #' + tracking_id + '] ' + name, eventData); 3024 } 3025 else { 3026 console.log('[Google GTM push to "'+datalayer_name+'"] ' + name, eventData); 3027 } 3028 } 3029 window[datalayer_name].push(eventData); 3030 3031 }; 3032 3033 var copyParams = Utils.copyProperties(eventParams, {}); // copy params because mapParamsToGTM can modify it 3034 3035 var params = mapParamsToGTM(ids,name,copyParams) 3036 3037 params.event_id = Utils.generateUniqueId(event); 3038 3039 _fireEvent(ids, name, params, event); 3040 } 3041 3042 function normalizeEventName(eventName) { 3043 3044 var matches = { 3045 ViewContent: 'view_item', 3046 AddToCart: 'add_to_cart', 3047 AddToWishList: 'add_to_wishlist', 3048 InitiateCheckout: 'begin_checkout', 3049 Purchase: 'purchase', 3050 Lead: 'generate_lead', 3051 CompleteRegistration: 'sign_up', 3052 AddPaymentInfo: 'set_checkout_option' 3053 }; 3054 3055 return matches.hasOwnProperty(eventName) ? matches[eventName] : eventName; 3056 3057 } 3058 3059 function mapParamsToGTM(tag,name,param) { 3060 //GA4 automatically collects a number of parameters for all events 3061 var hasGTM = false; 3062 3063 // end 3064 if (Array.isArray(tag)) { 3065 hasGTM = tag.some(function (element) { 3066 return isGTM(element); 3067 }); 3068 } else if(isGTM(tag)) { 3069 // tag is a string and matches GTM 3070 hasGTM = true; 3071 } 3072 if(hasGTM) { 3073 delete param.event_category; 3074 delete param.event_label; 3075 3076 delete param.analytics_storage; 3077 delete param.ad_storage; 3078 delete param.ad_user_data; 3079 delete param.ad_personalization; 3080 3081 if(name === 'search') { 3082 param['search'] = param.search_term; 3083 delete param.search_term; 3084 delete param.dynx_itemid; 3085 delete param.dynx_pagetype; 3086 delete param.dynx_totalvalue; 3087 } 3088 } 3089 return param; 3090 } 3091 3092 function isGTM(tag) { 3093 return tag.indexOf('GTM') === 0; 3094 } 3095 /** 3096 * Public API 3097 */ 3098 return { 3099 tag: function() { 3100 return "gtm"; 3101 }, 3102 isEnabled: function () { 3103 return options.hasOwnProperty('gtm'); 3104 }, 3105 disable: function () { 3106 initialized = false;
3107 }, 3108 updateEnhancedConversionData : function () { 3109 if (!initialized || !this.isEnabled()) { 3110 return; 3111 } 3112 if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.hasOwnProperty("userDataEnable") && options.tracking_analytics.userDataEnable) { 3113 var advanced = Utils.getAdvancedFormData(); 3114 if (Object.keys(advanced).length > 0) { 3115 window[datalayer_name].push({'user_data' : advanced}); 3116 } 3117 } 3118 }, 3119 loadPixel: function () { 3120 3121 if (initialized || !this.isEnabled() || !Utils.consentGiven('analytics')) { 3122 return; 3123 } 3124 datalayer_name = options.gtm.gtm_dataLayer_name ?? 'dataLayer'; 3125 3126 for (var i = 0; i < options.gtm.trackingIds.length; i++) { 3127 var trackingId = options.gtm.trackingIds[i]; 3128 if (!options.gtm.gtm_just_data_layer) { 3129 console.log('[PYS] Google Tag Manager container code loaded'); 3130 Utils.loadGTMScript(trackingId); 3131 break; 3132 } 3133 } 3134 if(options.gtm.gtm_just_data_layer) { 3135 console.warn && console.warn("[PYS] Google Tag Manager container code placement set to OFF !!!"); 3136 console.warn && console.warn("[PYS] Data layer codes are active but GTM container must be loaded using custom coding !!!"); 3137 // Push consent defaults even when GTM script loading is handled externally. 3138 // Fixes the case where gtm_just_data_layer=true with tracking IDs configured, 3139 // which previously skipped loadGTMScript() entirely and never pushed defaults. 3140 Utils.pushGTMConsentDefaults( datalayer_name ); 3141 if(options.gtm.trackingIds.length == 0){ 3142 Utils.loadGTMScript(); 3143 } 3144 } 3145 3146 if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.hasOwnProperty("userDataEnable") && options.tracking_analytics.userDataEnable){ 3147 var advanced = Utils.getAdvancedFormData(); 3148 if(Object.keys(advanced).length > 0){ 3149 window[datalayer_name].push({'user_data' : advanced}); 3150 } 3151 } 3152 3153 3154 var config = {}; 3155 3156 if(options.user_id && options.user_id != 0) { 3157 config.user_id = options.user_id; 3158 } 3159 3160 // Cross-Domain tracking 3161 3162 var ids = options.gtm.trackingIds; 3163 3164 3165 initialized = true; 3166 3167 Utils.fireStaticEvents('gtm'); 3168 }, 3169 3170 fireEvent: function (name, data) { 3171 3172 if (!initialized || !this.isEnabled()) { 3173 return false; 3174 } 3175 3176 data.delay = data.delay || 0; 3177 data.params = data.params || {}; 3178 3179 if (data.delay === 0) { 3180 3181 fireEvent(name, data); 3182 3183 } else { 3184 3185 setTimeout(function (name, params) { 3186 fireEvent(name, params); 3187 }, data.delay * 1000, name, data); 3188 3189 } 3190 3191 return true; 3192 3193 }, 3194 3195 onCommentEvent: function (event) { 3196 this.fireEvent(event.name, event); 3197 }, 3198 3199 onDownloadEvent: function (event) { 3200 this.fireEvent(event.name, event); 3201 }, 3202 3203 onFormEvent: function (event) { 3204 this.fireEvent(event.name, event); 3205 }, 3206 3207 onWooAddToCartOnButtonEvent: function (product_id, prod_info = null) { 3208 if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag())) 3209 return; 3210 var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()]); 3211 3212 if (window.pysWooProductData.hasOwnProperty(product_id)) { 3213 if (window.pysWooProductData[product_id].hasOwnProperty('gtm')) { 3214 Utils.copyProperties(window.pysWooProductData[product_id]['gtm'].params, event.params) 3215 this.fireEvent(event.name, event); 3216 } 3217 } 3218 3219 }, 3220 3221 onWooAddToCartOnSingleEvent: function (product_id, qty, product_type, is_external, $form, prod_info) { 3222 window.pysWooProductData = window.pysWooProductData || []; 3223 3224 if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag())) 3225 return; 3226 var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()]); 3227 3228 if (product_type === Utils.PRODUCT_VARIABLE && !options.gtm.wooVariableAsSimple) { 3229 product_id = parseInt($form.find('input[name="variation_id"]').val()); 3230 } 3231 3232 if (window.pysWooProductData.hasOwnProperty(product_id)) { 3233 if (window.pysWooProductData[product_id].hasOwnProperty('gtm')) { 3234 3235 Utils.copyProperties(window.pysWooProductData[product_id]['gtm'].params, event.params); 3236 3237 params = event.params.hasOwnProperty('ecommerce') ? event.params.ecommerce : event.params; 3238 3239 if(product_type === Utils.PRODUCT_GROUPED ) { 3240 var groupValue = 0; 3241 $form.find(".woocommerce-grouped-product-list .qty").each(function(index){ 3242 var childId = $(this).attr('name').replaceAll("quantity[","").replaceAll("]",""); 3243 var quantity = parseInt($(this).val()); 3244 if(isNaN(quantity)) { 3245 quantity = 0; 3246 } 3247 var childItem = window.pysWooProductData[product_id]['gtm'].grouped[childId];
3248 params.items.forEach(function(el,index,array) { 3249 if(el.id == childItem.content_id) { 3250 if(quantity > 0){ 3251 el.quantity = quantity; 3252 el.price = childItem.price; 3253 } else { 3254 array.splice(index, 1); 3255 } 3256 } 3257 }); 3258 groupValue += childItem.price * quantity; 3259 }); 3260 3261 if(options.woo.addToCartOnButtonValueEnabled && 3262 options.woo.addToCartOnButtonValueOption !== 'global' && 3263 params.hasOwnProperty('value')) { 3264 params.value = groupValue; 3265 } 3266 3267 if(groupValue == 0) return; // skip if no items selected 3268 } else { 3269 // update items qty param 3270 params.items[0].quantity = qty; 3271 } 3272 3273 // maybe customize value option 3274 if (options.woo.addToCartOnButtonValueEnabled && 3275 options.woo.addToCartOnButtonValueOption !== 'global' && 3276 product_type !== Utils.PRODUCT_GROUPED) 3277 { 3278 if(params.hasOwnProperty('value')) { 3279 params.value = params.items[0].price * qty; 3280 } 3281 3282 } 3283 3284 3285 this.fireEvent(event.name, event); 3286 } 3287 } 3288 3289 }, 3290 3291 onWooRemoveFromCartEvent: function (event) { 3292 3293 this.fireEvent(event.name, event); 3294 3295 }, 3296 3297 onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) { 3298 if(!options.dynamicEvents.edd_add_to_cart_on_button_click.hasOwnProperty(this.tag())) 3299 return; 3300 var event = Utils.clone(options.dynamicEvents.edd_add_to_cart_on_button_click[this.tag()]); 3301 3302 3303 if (window.pysEddProductData && window.pysEddProductData.hasOwnProperty(download_id)) { 3304 3305 var index; 3306 3307 if (price_index) { 3308 index = download_id + '_' + price_index; 3309 } else { 3310 index = download_id; 3311 } 3312 3313 if (window.pysEddProductData[download_id].hasOwnProperty(index)) { 3314 if (window.pysEddProductData[download_id][index].hasOwnProperty('gtm')) { 3315 3316 Utils.copyProperties(window.pysEddProductData[download_id][index]['gtm'].params, event.params); 3317 item = event.params.hasOwnProperty('ecommerce') ? event.params.ecommerce.items[0] : event.params.items[0]; 3318 // update items qty param 3319 item.quantity = qty; 3320 3321 this.fireEvent(event.name,event); 3322 3323 } 3324 } 3325 3326 } 3327 3328 }, 3329 3330 onEddRemoveFromCartEvent: function (event) { 3331 this.fireEvent(event.name, event); 3332 }, 3333 onPageScroll: function (event) { 3334 this.fireEvent(event.name, event); 3335 }, 3336 onTime: function (event) { 3337 this.fireEvent(event.name, event); 3338 }, 3339 }; 3340 3341 }(options); 3342 3343 var getPixelBySlag = function getPixelBySlag(slug) { 3344 switch (slug) { 3345 case "facebook": return window.pys.Facebook; 3346 case "ga": return window.pys.Analytics; 3347 case "gtm": return window.pys.GTM; 3348 case "bing": return window.pys.Bing; 3349 case "pinterest": return window.pys.Pinterest; 3350 case "reddit": return window.pys.Reddit; 3351 } 3352 } 3353
3354 window.pys = window.pys || {}; 3355 window.pys.Facebook = Facebook; 3356 window.pys.Analytics = Analytics; 3357 window.pys.GTM = GTM; 3358 window.pys.Utils = Utils; 3359 window.pys.getPixelBySlag = getPixelBySlag; 3360 3361 // Allow external scripts (e.g. generatePixelCode fragments) to refresh 3362 // the uniqueId cache for a given event key, so that each new add_to_cart 3363 // action gets a fresh shared ID across all pixels. 3364 window.pys.setEventUniqueId = function(idKey, newId) { 3365 uniqueId[idKey] = newId; 3366 }; 3367 3368 // Export getPixelBySlag globally for backward compatibility 3369 window.getPixelBySlag = getPixelBySlag; 3370 3371 3372 $(document).ready(function () { 3373 3374 if($("#pys_late_event").length > 0) { 3375 var dirAttr = $("#pys_late_event").attr("dir"); 3376 if (dirAttr) { 3377 try { 3378 var events = JSON.parse(dirAttr); 3379 } catch (e) { 3380 console.warn("Invalid JSON in pys_late_event dir attribute:", e); 3381 } 3382 } else { 3383 console.warn("pys_late_event dir attribute is undefined or empty"); 3384 } 3385 if (events) { 3386 for (var key in events) { 3387 var event = {}; 3388 event[events[key].e_id] = [events[key]]; 3389 if (options.staticEvents.hasOwnProperty(key)) { 3390 Object.assign(options.staticEvents[key], event); 3391 } else { 3392 options.staticEvents[key] = event; 3393 } 3394 } 3395 } 3396 } 3397 3398 var Pinterest = Utils.setupPinterestObject(); 3399 var Bing = Utils.setupBingObject(); 3400 var Reddit = Utils.setupRedditObject(); 3401 3402 if(options.hasOwnProperty('cookie')) 3403 { 3404 if(options.cookie.externalID_disabled_by_api || options.cookie.disabled_all_cookie) 3405 { 3406 Cookies.remove('pbid') 3407 } 3408 if(options.cookie.disabled_advanced_form_data_cookie || options.cookie.disabled_all_cookie) 3409 { 3410 Cookies.remove('pys_advanced_form_data') 3411 } 3412 if(options.cookie.disabled_landing_page_cookie || options.cookie.disabled_all_cookie) 3413 { 3414 Cookies.remove('pys_landing_page') 3415 Cookies.remove('last_pys_landing_page') 3416 } 3417 if(options.cookie.disabled_trafficsource_cookie || options.cookie.disabled_all_cookie) 3418 { 3419 Cookies.remove('pysTrafficSource') 3420 Cookies.remove('last_pysTrafficSource') 3421 } 3422 if(options.cookie.disabled_first_visit_cookie || options.cookie.disabled_all_cookie) 3423 { 3424 Cookies.remove('pys_first_visit') 3425 3426 } 3427 if(options.cookie.disabled_utmTerms_cookie || options.cookie.disabled_all_cookie) 3428 { 3429 $.each(Utils.utmTerms, function (index, name) { 3430 Cookies.remove('pys_' + name) 3431 }); 3432 $.each(Utils.utmTerms, function (index, name) { 3433 Cookies.remove('last_pys_' + name) 3434 }); 3435 } 3436 if(options.cookie.disabled_utmId_cookie || options.cookie.disabled_all_cookie) 3437 { 3438 $.each(Utils.utmId,function(index,name) { 3439 Cookies.remove('pys_' + name) 3440 }) 3441 $.each(Utils.utmId,function(index,name) { 3442 Cookies.remove('last_pys_' + name) 3443 }); 3444 } 3445 } 3446 3447 3448 if (options.gdpr.cookie_law_info_integration_enabled) { 3449 var cli_cookie = Cookies.get('cookieyes-consent') ?? Cookies.get('viewed_cookie_policy'); 3450 3451 if (typeof cli_cookie !== 'undefined') { 3452 if (cli_cookie === Cookies.get('cookieyes-consent') && getCookieYes('analytics') == 'yes') { 3453 Utils.manageCookies(); 3454 } else if (cli_cookie === Cookies.get('viewed_cookie_policy') && cli_cookie == 'yes') { 3455 Utils.manageCookies(); 3456 } 3457 } 3458 } 3459 3460 if ( options.gdpr.consent_magic_integration_enabled && typeof CS_Data !== "undefined" ) { 3461 if ( CS_Data.cs_script_cat.pys == CS_Data.cs_necessary_cat_id || CS_Data.cs_script_cat.pys == 0 ) { 3462 Utils.manageCookies(); 3463 } else if ( Cookies.get( 'cs_enabled_cookie_term' + CS_Data.test_prefix + '_' + CS_Data.cs_script_cat.pys ) == 'yes' ) { 3464 Utils.manageCookies(); 3465 } 3466 } else { 3467 Utils.manageCookies(); 3468 } 3469 3470 Utils.setupGdprCallbacks(); 3471 // page scroll event 3472 if ( options.dynamicEvents.hasOwnProperty("automatic_event_scroll") 3473 ) { 3474 3475 var singlePageScroll = function () { 3476 3477 3478 var docHeight = $(document).height() - $(window).height(); 3479 var isFired = false;
3480 3481 if (options.dynamicEvents.hasOwnProperty("automatic_event_scroll")) { 3482 var pixels = Object.keys(options.dynamicEvents.automatic_event_scroll); 3483 for(var i = 0;i<pixels.length;i++) { 3484 var event = Utils.clone(options.dynamicEvents.automatic_event_scroll[pixels[i]]); 3485 var scroll = Math.round(docHeight * event.scroll_percent / 100)// convert % to absolute positions 3486 3487 if(scroll < $(window).scrollTop()) { 3488 if ( pixels[i] !== 'reddit') { 3489 Utils.copyProperties( Utils.getRequestParams(), event.params ); 3490 } 3491 getPixelBySlag( pixels[ i ] ).onPageScroll( event ); 3492 isFired = true 3493 } 3494 } 3495 } 3496 if(isFired) { 3497 $(document).off("scroll",singlePageScroll); 3498 } 3499 } 3500 $(document).on("scroll",singlePageScroll); 3501 } 3502 3503 3504 if (options.dynamicEvents.hasOwnProperty("automatic_event_time_on_page")) { 3505 var pixels = Object.keys(options.dynamicEvents.automatic_event_time_on_page); 3506 var time = options.dynamicEvents.automatic_event_time_on_page[pixels[0]].time_on_page; // the same for all pixel 3507 setTimeout(function(){ 3508 for(var i = 0;i<pixels.length;i++) { 3509 var event = Utils.clone(options.dynamicEvents.automatic_event_time_on_page[pixels[i]]); 3510 3511 if ( pixels[i] !== 'reddit') {
3512 Utils.copyProperties(Utils.getRequestParams(), event.params); 3513 } 3514 getPixelBySlag(pixels[i]).onTime(event); 3515 } 3516 },time*1000); 3517 } 3518 3519 // setup Click Event 3520 if (options.dynamicEvents.hasOwnProperty("automatic_event_download")) { 3521 3522 $(document).onFirst('click', 'a, button, input[type="button"], input[type="submit"]', function (e) { 3523 3524 var $elem = $(this); 3525 3526 // Download 3527 if(options.dynamicEvents.hasOwnProperty("automatic_event_download") 3528 ) { 3529 var isFired = false; 3530 if ($elem.is('a')) { 3531 var href = $elem.attr('href'); 3532 if (typeof href !== "string") { 3533 return; 3534 } 3535 href = href.trim(); 3536 var extension = Utils.getLinkExtension(href); 3537 var track_download = false; 3538 3539 if (extension.length > 0) { 3540 3541 if(options.dynamicEvents.hasOwnProperty("automatic_event_download") ) { 3542 var pixels = Object.keys(options.dynamicEvents.automatic_event_download); 3543 for (var i = 0; i < pixels.length; i++) { 3544 var event = Utils.clone(options.dynamicEvents.automatic_event_download[pixels[i]]); 3545 var extensions = event.extensions; 3546 if (extensions.includes(extension)) { 3547 3548 if( pixels[i] == "tiktok" || pixels[i] == "reddit" ) { 3549 getPixelBySlag(pixels[i]).fireEvent(tikEvent.name, event); 3550 } else { 3551 if (options.enable_remove_download_url_param) { 3552 href = stripUrlQuery(href); 3553 } 3554 event.params.download_url = href; 3555 event.params.download_type = extension; 3556 event.params.download_name = Utils.getLinkFilename(href); 3557 getPixelBySlag(pixels[i]).onDownloadEvent(event); 3558 } 3559 3560 isFired = true; 3561 } 3562 } 3563 } 3564 } 3565 } 3566 if(isFired) { // prevent duplicate events on the same element 3567 return; 3568 } 3569 } 3570 }); 3571 } 3572 3573 3574 // setup Dynamic events 3575 $.each(options.triggerEventTypes, function (triggerType, events) { 3576 3577 $.each(events, function (eventId, triggers) { 3578 3579 switch (triggerType) { 3580 case 'url_click': 3581 //@see: Utils.setupURLClickEvents() 3582 break; 3583 3584 case 'css_click': 3585 Utils.setupCSSClickEvents(eventId, triggers); 3586 break; 3587 3588 case 'css_mouseover': 3589 Utils.setupMouseOverClickEvents(eventId, triggers); 3590 break; 3591 3592 case 'scroll_pos': 3593 Utils.setupScrollPosEvents(eventId, triggers); 3594 break; 3595 case 'comment': 3596 Utils.setupCommentEvents(eventId, triggers); 3597 break; 3598 } 3599 3600 }); 3601 3602 }); 3603 // setup WooCommerce events 3604 if (options.woo.enabled) { 3605 3606 // WooCommerce AddToCart 3607 if (options.dynamicEvents.hasOwnProperty("woo_add_to_cart_on_button_click") 3608 && options.woo.hasOwnProperty("addToCartCatchMethod") 3609 && options.woo.addToCartCatchMethod === "add_cart_js" 3610 ) { 3611 3612 // Loop, any kind of "simple" product, except external 3613 $('.add_to_cart_button:not(.product_type_variable,.product_type_bundle,.single_add_to_cart_button)').on("click",function (e) { 3614 3615 var product_id = $(this).data('product_id'); 3616 if (typeof product_id !== 'undefined') { 3617 if (options.dynamicEvents.hasOwnProperty("woo_add_to_cart_on_button_click")) { 3618 var tmpEventID = pys_generate_token(); 3619 $.each(options.dynamicEvents.woo_add_to_cart_on_button_click, function (i, tag) { 3620 tag.eventID = tmpEventID; 3621 // Also refresh the uniqueId cache so server-API path 3622 // (ajaxForServerStaticEvent) gets the same fresh ID. 3623 var idKey = tag.hasOwnProperty('custom_event_post_id') ? tag.custom_event_post_id : tag.e_id; 3624 uniqueId[idKey] = tmpEventID; 3625 }); 3626 } 3627 if (typeof product_id !== 'undefined') { 3628 Facebook.onWooAddToCartOnButtonEvent(product_id); 3629 Analytics.onWooAddToCartOnButtonEvent(product_id); 3630 GTM.onWooAddToCartOnButtonEvent(product_id); 3631 Pinterest.onWooAddToCartOnButtonEvent(product_id); 3632 Bing.onWooAddToCartOnButtonEvent(product_id); 3633 Reddit.onWooAddToCartOnButtonEvent(product_id); 3634 } 3635 } 3636 }); 3637 3638 // Single Product 3639 // tap try to https://stackoverflow.com/questions/30990967/on-tap-click-event-firing-twice-how-to-avoid-it 3640 // $(document) not work 3641 $('body').onFirst('click','button.single_add_to_cart_button,.single_add_to_cart_button',function (e) { 3642 3643 var $button = $(this); 3644 3645 if ($button.hasClass('disabled')) { 3646 return; 3647 } 3648 3649 var $form = $button.closest('form'); 3650 3651 var product_type = Utils.PRODUCT_SIMPLE; 3652 3653 if ($form.length === 0) { 3654 return ; 3655 } else if ($form.hasClass('variations_form')) { 3656 product_type = Utils.PRODUCT_VARIABLE; 3657 } else if($form.hasClass('bundle_form')) { 3658 product_type = Utils.PRODUCT_BUNDLE; 3659 } else if($form.hasClass('grouped_form')) { 3660 product_type = Utils.PRODUCT_GROUPED; 3661 } 3662 3663 3664 3665 3666 var product_id; 3667 var qty; 3668 3669 if (product_type === Utils.PRODUCT_GROUPED) { 3670 qty = 1; 3671 product_id = parseInt($form.find('*[name="add-to-cart"]').val()); 3672 } else if (product_type === Utils.PRODUCT_VARIABLE) { 3673 product_id = parseInt($form.find('*[name="add-to-cart"]').val()); 3674 var qtyTag = $form.find('input[name="quantity"]'); 3675 if(qtyTag.length <= 0) { 3676 qtyTag = $form.find('select[name="quantity"]'); 3677 } 3678 qty = parseInt(qtyTag.val()); 3679 } else { 3680 product_id = parseInt($form.find('*[name="add-to-cart"]').val()); 3681 var qtyTag = $form.find('input[name="quantity"]'); 3682 if(qtyTag.length <= 0) { 3683 qtyTag = $form.find('select[name="quantity"]'); 3684 } 3685 qty = parseInt(qtyTag.val()); 3686 } 3687 3688 if(options.dynamicEvents.hasOwnProperty("woo_add_to_cart_on_button_click")){ 3689 var tmpEventID = pys_generate_token(); 3690 $.each(options.dynamicEvents.woo_add_to_cart_on_button_click, function (i, tag) { 3691 tag.eventID = tmpEventID; 3692 // Also refresh the uniqueId cache so server-API path 3693 // (ajaxForServerStaticEvent) gets the same fresh ID. 3694 var idKey = tag.hasOwnProperty('custom_event_post_id') ? tag.custom_event_post_id : tag.e_id; 3695 uniqueId[idKey] = tmpEventID; 3696 }); 3697 } 3698 3699 Facebook.onWooAddToCartOnSingleEvent(product_id, qty, product_type, $form); 3700 Analytics.onWooAddToCartOnSingleEvent(product_id, qty, product_type, $form); 3701 3702 GTM.onWooAddToCartOnSingleEvent(product_id, qty, product_type, $form); 3703 3704 Pinterest.onWooAddToCartOnSingleEvent(product_id, qty, product_type, false, $form); 3705 Bing.onWooAddToCartOnSingleEvent(product_id, qty, product_type, false, $form); 3706 Reddit.onWooAddToCartOnSingleEvent(product_id, qty, product_type, false, $form); 3707 3708 }); 3709 3710 } 3711 3712 // WooCommerce RemoveFromCart 3713 if (options.dynamicEvents.hasOwnProperty("woo_remove_from_cart")) { 3714 3715 $('body').on('click', options.woo.removeFromCartSelector, function (e) { 3716 3717 var $a = $(e.currentTarget), 3718 href = $a.attr('href'); 3719 3720 // extract cart item hash from remove button URL 3721 var regex = new RegExp("[\\?&]remove_item=([^&#]*)"), 3722 results = regex.exec(href); 3723 3724 if (results !== null) { 3725 3726 var item_hash = results[1]; 3727 3728 if (options.dynamicEvents["woo_remove_from_cart"].hasOwnProperty(item_hash)) { 3729 var events = options.dynamicEvents["woo_remove_from_cart"][item_hash]; 3730 Utils.fireEventForAllPixel("onWooRemoveFromCartEvent",events) 3731 } 3732 3733 } 3734 3735 }); 3736 } 3737 } 3738 3739 // setup EDD events 3740 if (options.edd.enabled) { 3741 3742 // EDD AddToCart 3743 if (options.dynamicEvents.hasOwnProperty("edd_add_to_cart_on_button_click")) { 3744 3745 $('form.edd_download_purchase_form .edd-add-to-cart').on("click",function (e) { 3746 3747 var $button = $(this); 3748 var $form = $button.closest('form'); 3749 var variable_price = $button.data('variablePrice'); // yes/no 3750 var price_mode = $button.data('priceMode'); // single/multi 3751 var ids = []; 3752 var quantities = []; 3753 var qty; 3754 var id; 3755 3756 if (variable_price === 'yes' && price_mode === 'multi') { 3757 3758 id = $form.find('input[name="download_id"]').val(); 3759 3760 // get selected variants 3761 $.each($form.find('input[name="edd_options[price_id][]"]:checked'), function (i, el) { 3762 ids.push(id + '_' + $(el).val()); 3763 }); 3764 3765 // get qty for selected variants 3766 $.each(ids, function (i, variant_id) { 3767 3768 var variant_index = variant_id.split('_', 2); 3769 qty = $form.find('input[name="edd_download_quantity_' + variant_index[1] + '"]').val(); 3770 3771 if (typeof qty !== 'undefined') { 3772 quantities.push(qty); 3773 } else { 3774 quantities.push(1); 3775 } 3776 3777 }); 3778 3779 } else if (variable_price === 'yes' && price_mode === 'single') { 3780 3781 id = $form.find('input[name="download_id"]').val(); 3782 ids.push(id + '_' + $form.find('input[name="edd_options[price_id][]"]:checked').val()); 3783 3784 qty = $form.find('input[name="edd_download_quantity"]').val(); 3785 3786 if (typeof qty !== 'undefined') { 3787 quantities.push(qty); 3788 } else { 3789 quantities.push(1); 3790 } 3791 3792 } else { 3793 3794 ids.push($button.data('downloadId')); 3795 3796 qty = $form.find('input[name="edd_download_quantity"]').val(); 3797 3798 if (typeof qty !== 'undefined') { 3799 quantities.push(qty); 3800 } else { 3801 quantities.push(1); 3802 } 3803 } 3804 3805 // fire event for each download/variant 3806 $.each(ids, function (i, download_id) { 3807 3808 var q = parseInt(quantities[i]); 3809 var variant_index = download_id.toString().split('_', 2); 3810 var price_index; 3811 3812 if (variant_index.length === 2) { 3813 download_id = variant_index[0]; 3814 price_index = variant_index[1]; 3815 } 3816 3817 Facebook.onEddAddToCartOnButtonEvent(download_id, price_index, q); 3818 Analytics.onEddAddToCartOnButtonEvent(download_id, price_index, q); 3819 GTM.onEddAddToCartOnButtonEvent(download_id, price_index, q); 3820 Pinterest.onEddAddToCartOnButtonEvent(download_id, price_index, q); 3821 Bing.onEddAddToCartOnButtonEvent(download_id, price_index, q); 3822 Reddit.onEddAddToCartOnButtonEvent(download_id, price_index, q); 3823 }); 3824 3825 }); 3826 3827 } 3828 3829 3830 // EDD RemoveFromCart 3831 if (options.dynamicEvents.hasOwnProperty("edd_remove_from_cart") ) { 3832 3833 $('form#edd_checkout_cart_form .edd_cart_remove_item_btn').on("click",function (e) { 3834 3835 var href = $(this).attr('href'); 3836 if(href) { 3837 var key = href.substring(href.indexOf('=') + 1).charAt(0); 3838 if (options.dynamicEvents.edd_remove_from_cart.hasOwnProperty(key)) { 3839 var events = options.dynamicEvents.edd_remove_from_cart[key]; 3840 Utils.fireEventForAllPixel("onEddRemoveFromCartEvent",events) 3841 } 3842 } 3843 }); 3844 3845 } 3846 3847 } 3848 3849 // setup Comment Event 3850 if (options.dynamicEvents.hasOwnProperty("automatic_event_c
3850omment") 3851 ) { 3852 3853 $('form.comment-form').on("submit",function () { 3854 if (options.dynamicEvents.hasOwnProperty("automatic_event_comment")) { 3855 var pixels = Object.keys(options.dynamicEvents.automatic_event_comment); 3856 for (var i = 0; i < pixels.length; i++) { 3857 var event = Utils.clone(options.dynamicEvents.automatic_event_comment[pixels[i]]); 3858 if ( pixels[i] !== 'reddit') { 3859 Utils.copyProperties(Utils.getRequestParams(), event.params); 3860 } 3861 getPixelBySlag(pixels[i]).onCommentEvent(event); 3862 } 3863 } 3864 }); 3865 3866 } 3867 3868 3869 // setup Form Event 3870 if ( options.dynamicEvents.hasOwnProperty("automatic_event_form")) { 3871 3872 $(document).onFirst('submit', 'form', function (e) { 3873 3874 var $form = $(this); 3875 3876 // exclude WP forms 3877 const formClass = $form.attr('class') || ''; 3878 const formRole = ($form.attr('role') || '').toLowerCase(); 3879 const formId = $form.attr('id'); 3880 3881 if ( 3882 $form.hasClass('comment-form') || 3883 $form.hasClass('search-form') || 3884 $form.hasClass('woocommerce-ordering') || 3885 formClass.toLowerCase().includes('search') || formClass.toLowerCase().includes('add-to-cart') || 3886 formRole === 'search' || 3887 formId === 'adminbarsearch' 3888 ) { 3889 return; 3890 } 3891 3892 // exclude Woo forms 3893 if ($form.hasClass('woocommerce-product-search') || $form.hasClass('cart') || $form.hasClass('woocommerce-cart-form') || 3894 $form.hasClass('woocommerce-shipping-calculator') || $form.hasClass('checkout') || $form.hasClass('checkout_coupon')) { 3895 return; 3896 } 3897 3898 // exclude EDD forms 3899 if ($form.hasClass('edd_form') || $form.hasClass('edd_download_purchase_form')) { 3900 return; 3901 } 3902// exclude CF7 forms 3903 if ($form.hasClass('wpcf7-form')) { 3904 return; 3905 } 3906 // exclude Forminator forms 3907 if ($form.hasClass('forminator-custom-form') || $form.hasClass('forminator_ajax')) { 3908 return; 3909 } 3910 // exclude WPforms forms 3911 if ($form.hasClass('wpforms-form') || $form.hasClass('wpforms-ajax-form')) { 3912 return; 3913 } 3914 // exclude Formidable forms 3915 /*if ($form.hasClass('frm-show-form')) { 3916 return; 3917 }*/ 3918 // exclude Ninja Forms forms 3919 if ($form.parent().hasClass('nf-form-layout')) { 3920 return; 3921 } 3922 // exclude Fluent forms 3923 if ($form.hasClass('frm-fluent-form')) { 3924 return; 3925 } 3926 if(!options.enable_success_send_form) { 3927 var params = { 3928 form_id: $form.attr('id'), 3929 form_class: $form.attr('class'), 3930 text: $form.find('[type="submit"]').is('input') ? 3931 $form.find('[type="submit"]').val() : $form.find('[type="submit"]').text() 3932 }; 3933 3934 if (options.dynamicEvents.hasOwnProperty("automatic_event_form")) { 3935 var pixels = Object.keys(options.dynamicEvents.automatic_event_form); 3936 for (var i = 0; i < pixels.length; i++) { 3937 var event = Utils.clone(options.dynamicEvents.automatic_event_form[pixels[i]]); 3938 3939 if (pixels[i] === "tiktok" || pixels[i] === "reddit") { 3940 getPixelBySlag(pixels[i]).fireEvent(event.name, event); 3941 } else { 3942 Utils.copyProperties(params, event.params,) 3943 Utils.copyProperties(Utils.getRequestParam
3943s(), event.params); 3944 getPixelBySlag(pixels[i]).onFormEvent(event); 3945 } 3946 } 3947 } 3948 } 3949 }); 3950 3951 document.addEventListener( 'wpcf7mailsent', function( event ) { 3952 var form_id = event.detail.contactFormId; 3953 sendFormAction($(event.target), form_id); 3954 }, false ); 3955 //Forminator 3956 $(document).on( 'forminator:form:submit:success', function( event ){ 3957 var form_id = $(event.target).find('input[name="form_id"]').val(); 3958 sendFormAction($(event.target), form_id); 3959 }); 3960 3961 //WPForm 3962 $('form.wpforms-form').on('wpformsAjaxSubmitSuccess', (event) => { 3963 var form_id = $(event.target).attr('data-formid'); 3964 sendFormAction($(event.target), form_id); 3965 }) 3966 $(document).on( 'frmFormComplete', function( event, form, response ) { 3967 const form_id = $(form).find('input[name="form_id"]').val(); 3968 sendFormAction($(event.target), form_id); 3969 }); 3970 // Ninja Forms 3971 $(document).onFirst('nfFormSubmitResponse', function (event, data) { 3972 const form_id = data.response.data.form_id; 3973 sendFormAction($(event.target), form_id); 3974 }); 3975 3976 var fluentForms = $('form.frm-fluent-form'); 3977 fluentForms.each(function() { 3978 var $form = $(this); 3979 $form.on('fluentform_submission_success', function(event) { 3980 var $formItem = $(this); 3981 var form_id = $formItem.attr('data-form_id'); 3982 sendFormAction($(event.target), form_id); 3983 }); 3984 }); 3985 3986 } 3987 3988 3989 // load pixel APIs 3990 Utils.loadPixels(); 3991 // setup Enrich content 3992 if(Utils.isCheckoutPage()) { 3993 Utils.addCheckoutFields(); 3994 } 3995 }); 3996 3997 var sendFormAction = function (form_target, formId){ 3998 var params = { 3999 form_id: formId, 4000 text: form_target.find('[type="submit"]').is('input') ? form_target.find('[type="submit"]').val() : 4001 form_target.find('.forminator-button-submit').text() != '' ? form_target.find('.forminator-button-submit').text() : 4002 form_target.find('[type="submit"]').text() 4003 }; 4004 4005 if (options.dynamicEvents.hasOwnProperty("automatic_event_form")) { 4006 var pixels = Object.keys(options.dynamicEvents.automatic_event_form); 4007 for (var i = 0; i < pixels.length; i++) { 4008 var event = options.dynamicEvents.automatic_event_form[pixels[i]]; 4009 if (pixels[i] === "tiktok" || pixels[i] === "reddit") { 4010 getPixelBySlag(pixels[i]).fireEvent(event.name, event); 4011 } else { 4012 Utils.copyProperties(params, event.params)
4013 Utils.copyProperties(Utils.getRequestParams(), event.params); 4014 getPixelBySlag(pixels[i]).onFormEvent(event); 4015 } 4016 } 4017 } 4018 } 4019 4020}(jQuery, pysOptions); 4021 4022function pys_generate_token() { 4023 return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c => 4024 (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) 4025 ); 4026} 4027 4028function getBundlePriceOnSingleProduct(data) { 4029 var items_sum = 0; 4030 jQuery(".bundle_form .bundled_product").each(function(index){ 4031 var id = jQuery(this).find(".cart").data("bundled_item_id"); 4032 var item_price = data.prices[id]; 4033 var item_quantity = jQuery(this).find(".bundled_qty").val(); 4034 if(!jQuery(this).hasClass("bundled_item_optional") || 4035 jQuery(this).find(".bundled_product_optional_checkbox input").prop('checked')) { 4036 items_sum += item_price*item_quantity; 4037 } 4038 }); 4039 return items_sum; 4040} 4041function getUrlParameter(sParam) { 4042 var sPageURL = window.location.search.substring(1), 4043 sURLVariables = sPageURL.split('&'), 4044 sParameterName, 4045 i; 4046 4047 for (i = 0; i < sURLVariables.length; i++) { 4048 sParameterName = sURLVariables[i].split('='); 4049 4050 if (sParameterName[0] === sParam) { 4051 return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]); 4052 } 4053 } 4054 return false; 4055}; 4056function getCookieYes(key) { 4057 const cookiesObj = document.cookie 4058 .split(";") 4059 .reduce((ac, cv) => { 4060 const [k, v] = cv.split("="); 4061 if (k && v) ac[k.trim()] = v; 4062 return ac; 4063 }, {}); 4064 const consentCookie = cookiesObj["cookieyes-consent"] || cookiesObj["wt_consent"]; 4065 if (!consentCookie) return undefined; 4066 const { [key]: value } = consentCookie 4067 .split(",") 4068 .reduce((obj, pair) => { 4069 const [k, v] = pair.split(":"); 4070 if (k && v) obj[k] = v; 4071 return obj; 4072 }, {}); 4073 return value; 4074} 4075function getRootDomain(useSubdomain = false) { 4076 const hostname = window.location.hostname; // Get the current hostname 4077 // Check if tldjs is defined before using it 4078 if (typeof tldjs === "undefined") { 4079 console.warn("tldjs is not defined"); 4080 return hostname; // Return hostname as a fallback 4081 } 4082 4083 const rootDomain = tldjs.getDomain(hostname); // Use tldjs to extract the root domain 4084 4085 // Return the root domain with or without a leading dot based on useSubdomain 4086 return rootDomain ? (useSubdomain ? '.' + rootDomain : rootDomain) : hostname; 4087}
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.