1/** 2 * Facebook Pixel Events - External JavaScript Handler 3 * 4 * This script fires pixel events in an isolated execution context, 5 * ensuring events are sent even if other plugins cause JavaScript errors. 6 * 7 * @package FacebookCommerce 8 */ 9 10(function() { 11 'use strict'; 12 13 // Early exit if no data from PHP 14 if (typeof wc_facebook_pixel_data === 'undefined') { 15 return; 16 } 17 18 var data = wc_facebook_pixel_data; 19 var firedEvents = {}; 20 21 /** 22 * Build event data object for fbq() 23 * 24 * @param {Object} event Event object from PHP 25 * @return {Object} Prepared event data 26 */ 27 function buildEventData(event) { 28 return { 29 method: event.method || 'track', 30 name: event.name, 31 params: event.params || {}, 32 eventId: event.eventId || null 33 }; 34 } 35 36 /** 37 * Check if event should be skipped (already fired) 38 * 39 * @param {string|null} eventId Event ID for deduplication 40 * @return {boolean} True if should skip 41 */ 42 function shouldSkipEvent(eventId) { 43 return eventId && firedEvents[eventId]; 44 } 45 46 /** 47 * Mark event as fired for deduplication 48 * 49 * @param {string|null} eventId Event ID 50 */ 51 function markEventFired(eventId) { 52 if (eventId) { 53 firedEvents[eventId] = true; 54 } 55 } 56 57 /** 58 * Log warning to console (with safety check) 59 * 60 * @param {string} message Warning message 61 * @param {*} data Additional data to log 62 */ 63 function logWarning(message, data) { 64 if (typeof console !== 'undefined' && console.warn) { 65 console.warn('[FB Pixel]', message, data); 66 } 67 } 68 69 /** 70 * Fire a single event using fbq() 71 * 72 * @param {Object} event Event object with name, params, method, eventId 73 */ 74 function fireEvent(event) { 75 var eventData = buildEventData(event); 76 77 // Skip if already fired (deduplication) 78 if (shouldSkipEvent(eventData.eventId)) { 79 return; 80 } 81 82 // Skip if fbq not available 83 if (typeof fbq !== 'function') { 84 logWarning('fbq not available, skipping event:', eventData.name); 85 return; 86 } 87 88 try { 89 var params = eventData.params; 90 91 // Fire the event with eventID as 4th argument for deduplication 92 if (eventData.eventId) { 93 fbq(eventData.method, eventData.name, params, {eventID: eventData.eventId}); 94 } else { 95 fbq(eventData.method, eventData.name, params); 96 } 97 98 markEventFired(eventData.eventId); 99 100 } catch (e) { 101 logWarning('Event error: ' + eventData.name, e); 102 } 103 } 104 105 /** 106 * Fire all queued events from PHP 107 */ 108 function fireQueuedEvents() { 109 var events = data.eventQueue; 110 111 if (!events || !Array.isArray(events)) { 112 return; 113 } 114 115 for (var i = 0; i < events.length; i++) { 116 try { 117 fireEvent(events[i]); 118 } catch (e) { 119 logWarning('fireQueuedEvents loop error:', e); 120 } 121 } 122 123 // Clear events after firing to prevent duplicate firing 124 data.eventQueue = []; 125 } 126 127 /** 128 * Initialize pixel event handling. 129 * 130 * If fbq() is already available, fires queued events immediately. 131 * If not (e.g. consent manager blocking the SDK), uses Object.defineProperty 132 * to set a trap on window.fbq â our handler fires automatically the moment 133 * fbq is assigned, with zero overhead in between. No polling, no timers. 134 */ 135 function init() { 136 if (typeof fbq === 'function') { 137 fireQueuedEvents(); 138 return; 139 } 140 141 // fbq doesn't exist yet â watch for it (zero overhead, no timers). 142 // Consent managers block fbq until the 143 // user accepts. This fires the moment they assign window.fbq. 144 var _fbq = window.fbq; 145 Object.defineProperty(window, 'fbq', { 146 configurable: true, 147 enumerable: true, 148 get: function() { return _fbq; }, 149 set: function(value) { 150 _fbq = value; 151 if (typeof value === 'function') { 152 // Restore normal property so FB SDK works normally 153 Object.defineProperty(window, 'fbq', { 154 configurable: true, 155 enumerable: true, 156 writable: true, 157 value: value 158 }); 159 setTimeout(fireQueuedEvents, 0); 160 } 161 } 162 }); 163 } 164 165 // Start 166 if (document.readyState === 'complete') { 167 init(); 168 } else { 169 window.addEventListener('load', init); 170 } 171 172})();
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.