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