|
60 | 60 | constructor = function () { |
61 | 61 | var self = this, |
62 | 62 | isInitialized = false, |
63 | | - reportingService = null; |
| 63 | + reportingService = null, |
| 64 | + settings, |
| 65 | + productAttributeMapping; |
64 | 66 |
|
65 | 67 | self.name = name; |
66 | 68 |
|
67 | | - function initForwarder(settings, service, testMode, trackerId, userAttributes, userIdentities) { |
| 69 | + function initForwarder(forwarderSettings, service, testMode, trackerId, userAttributes, userIdentities) { |
| 70 | + settings = forwarderSettings; |
68 | 71 | reportingService = service; |
69 | 72 |
|
70 | 73 | SupportedCommerceTypes = [ |
|
107 | 110 | fbq.disablePushState = true; |
108 | 111 | } |
109 | 112 | fbq('init', settings.pixelId, visitorData); |
| 113 | + |
| 114 | + loadMappings(); |
110 | 115 |
|
111 | 116 | isInitialized = true; |
112 | 117 |
|
|
118 | 123 | } |
119 | 124 | } |
120 | 125 |
|
| 126 | + function loadMappings() { |
| 127 | + productAttributeMapping = settings.productAttributeMapping |
| 128 | + ? JSON.parse(settings.productAttributeMapping.replace(/"/g, '"')) |
| 129 | + : []; |
| 130 | + } |
| 131 | + |
121 | 132 | function processEvent(event) { |
122 | 133 | var reportEvent = false; |
123 | 134 |
|
|
212 | 223 |
|
213 | 224 | } |
214 | 225 | else if (event.ProductAction.ProductActionType == mParticle.ProductActionType.Checkout || |
215 | | - event.ProductAction.ProductActionType == mParticle.ProductActionType.Purchase) { |
| 226 | + event.ProductAction.ProductActionType == mParticle.ProductActionType.Purchase) { |
216 | 227 |
|
217 | 228 | eventName = event.ProductAction.ProductActionType == mParticle.ProductActionType.Checkout ? CHECKOUT_EVENT_NAME : PURCHASE_EVENT_NAME; |
218 | 229 |
|
|
227 | 238 | return sum; |
228 | 239 | }, 0); |
229 | 240 | params['num_items'] = num_items; |
| 241 | + |
| 242 | + if (event.ProductAction.TransactionId) { |
| 243 | + params['order_id'] = event.ProductAction.TransactionId; |
| 244 | + } |
| 245 | + |
| 246 | + // Build contents array for Purchase events |
| 247 | + if (event.ProductAction.ProductActionType == mParticle.ProductActionType.Purchase) { |
| 248 | + var contents = buildProductContents(event.ProductAction.ProductList); |
| 249 | + if (contents && contents.length > 0) { |
| 250 | + params['contents'] = contents; |
| 251 | + } |
| 252 | + } |
230 | 253 | } |
231 | 254 | else if (event.ProductAction.ProductActionType == mParticle.ProductActionType.RemoveFromCart) { |
232 | 255 | eventName = REMOVE_FROM_CART_EVENT_NAME; |
|
323 | 346 | return null; |
324 | 347 | } |
325 | 348 |
|
| 349 | + /** |
| 350 | + * Builds contents array for Facebook Pixel commerce events. |
| 351 | + * Creates a nested array of content items with product details. |
| 352 | + * |
| 353 | + * @param {Array} productList - Array of products from event.ProductAction.ProductList |
| 354 | + * @returns {Array} Array of content objects for Facebook Pixel |
| 355 | + */ |
| 356 | + function buildProductContents(productList) { |
| 357 | + if (!productList || productList.length === 0) { |
| 358 | + return []; |
| 359 | + } |
| 360 | + |
| 361 | + return productList |
| 362 | + .filter(function(product) { |
| 363 | + return product && product.Sku; |
| 364 | + }) |
| 365 | + .map(function(product) { |
| 366 | + var contentItem = { |
| 367 | + id: product.Sku, |
| 368 | + quantity: isNumeric(product.Quantity) ? product.Quantity : 1, |
| 369 | + name: product.Name, |
| 370 | + brand: product.Brand, |
| 371 | + category: product.Category, |
| 372 | + variant: product.Variant, |
| 373 | + item_price: isNumeric(product.Price) ? product.Price : null |
| 374 | + }; |
| 375 | + |
| 376 | + // Apply configured mappings to custom attributes |
| 377 | + productAttributeMapping.forEach(function(productMapping) { |
| 378 | + if (!isobject(productMapping) || !productMapping.map || !productMapping.value) { |
| 379 | + return; |
| 380 | + } |
| 381 | + |
| 382 | + var sourceField = productMapping.map; |
| 383 | + var facebookFieldName = productMapping.value; |
| 384 | + var value = null; |
| 385 | + |
| 386 | + // Check for Product level field first |
| 387 | + if (product.hasOwnProperty(sourceField)) { |
| 388 | + value = product[sourceField]; |
| 389 | + } |
| 390 | + // then check for Product.Attributes level field |
| 391 | + else if (product.Attributes && product.Attributes[sourceField]) { |
| 392 | + value = product.Attributes[sourceField]; |
| 393 | + } |
| 394 | + |
| 395 | + if (value !== null && value !== undefined) { |
| 396 | + contentItem[facebookFieldName] = value; |
| 397 | + } |
| 398 | + }); |
| 399 | + return contentItem; |
| 400 | + }); |
| 401 | + } |
| 402 | + |
326 | 403 | // https://developers.facebook.com/docs/marketing-api/conversions-api/deduplicate-pixel-and-server-events#event-deduplication-options |
327 | 404 | function createEventId(event) { |
328 | 405 | return { |
|
0 commit comments