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