Skip to content

Commit c0a6bd0

Browse files
authored
Add dynamic user data to Pixel events (#754)
* Add dynamic user data to events * use a pixel init flag global variable * combine constants
1 parent 8105bd3 commit c0a6bd0

File tree

5 files changed

+246
-36
lines changed

5 files changed

+246
-36
lines changed

app/code/Meta/Conversion/Block/Pixel/Common.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
namespace Meta\Conversion\Block\Pixel;
2222

23+
use Exception;
2324
use Meta\BusinessExtension\Helper\FBEHelper;
2425
use Meta\Conversion\Helper\MagentoDataHelper;
2526
use Meta\BusinessExtension\Model\System\Config as SystemConfig;
@@ -226,6 +227,38 @@ public function getContentId(Product $product)
226227
return $this->magentoDataHelper->getContentId($product);
227228
}
228229

230+
/**
231+
* Get automatic matching flag
232+
*
233+
* @return bool|null
234+
*/
235+
public function getAutomaticMatchingFlag(): ?bool
236+
{
237+
try {
238+
$storeId = $this->_storeManager->getStore()->getId();
239+
$settingsAsString = $this->systemConfig->getPixelAamSettings($storeId);
240+
if ($settingsAsString) {
241+
$settingsAsArray = json_decode($settingsAsString, true);
242+
if ($settingsAsArray && isset($settingsAsArray['enableAutomaticMatching'])) {
243+
return (bool)$settingsAsArray['enableAutomaticMatching'];
244+
}
245+
}
246+
} catch (Exception $e) {
247+
$this->fbeHelper->logException($e);
248+
}
249+
return null;
250+
}
251+
252+
/**
253+
* Get user data URL
254+
*
255+
* @return string
256+
*/
257+
public function getUserDataUrl(): string
258+
{
259+
return $this->getUrl('fbe/pixel/userData');
260+
}
261+
229262
/**
230263
* Get tracker url
231264
*
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Copyright (c) Meta Platforms, Inc. and affiliates.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
namespace Meta\Conversion\Controller\Pixel;
22+
23+
use Exception;
24+
use Magento\Customer\Model\Customer;
25+
use Magento\Customer\Model\Session as CustomerSession;
26+
use Magento\Framework\App\Action\HttpGetActionInterface;
27+
use Meta\BusinessExtension\Helper\FBEHelper;
28+
use Meta\Conversion\Helper\AAMFieldsExtractorHelper;
29+
use Magento\Framework\Controller\Result\JsonFactory;
30+
use Magento\Framework\Controller\Result\Json;
31+
32+
class UserData implements HttpGetActionInterface
33+
{
34+
/**
35+
* @var JsonFactory
36+
*/
37+
private JsonFactory $jsonFactory;
38+
39+
/**
40+
* @var FBEHelper
41+
*/
42+
private $fbeHelper;
43+
44+
/**
45+
* @var CustomerSession
46+
*/
47+
private CustomerSession $customerSession;
48+
49+
/**
50+
* @var AAMFieldsExtractorHelper
51+
*/
52+
private AAMFieldsExtractorHelper $aamFieldsExtractorHelper;
53+
54+
/**
55+
* Constructor
56+
*
57+
* @param JsonFactory $jsonFactory
58+
* @param FBEHelper $fbeHelper
59+
* @param CustomerSession $customerSession
60+
* @param AAMFieldsExtractorHelper $aamFieldsExtractorHelper
61+
*/
62+
public function __construct(
63+
JsonFactory $jsonFactory,
64+
FBEHelper $fbeHelper,
65+
CustomerSession $customerSession,
66+
AAMFieldsExtractorHelper $aamFieldsExtractorHelper
67+
) {
68+
$this->jsonFactory = $jsonFactory;
69+
$this->fbeHelper = $fbeHelper;
70+
$this->customerSession = $customerSession;
71+
$this->aamFieldsExtractorHelper = $aamFieldsExtractorHelper;
72+
}
73+
74+
/**
75+
* Get logged in customer
76+
*
77+
* @return Customer|null
78+
*/
79+
public function getCustomer(): ?Customer
80+
{
81+
return $this->customerSession->isLoggedIn() ? $this->customerSession->getCustomer() : null;
82+
}
83+
84+
/**
85+
* Get user data
86+
*
87+
* @return array|null
88+
*/
89+
private function getUserData(): ?array
90+
{
91+
$userData = $this->aamFieldsExtractorHelper->getNormalizedUserData($this->getCustomer());
92+
return empty($userData) ? null : $userData;
93+
}
94+
95+
/**
96+
* Get user data
97+
*
98+
* @return Json
99+
*/
100+
public function execute(): Json
101+
{
102+
$response = [];
103+
try {
104+
$response = [
105+
'user_data' => $this->getUserData(),
106+
'success' => true,
107+
];
108+
} catch (Exception $e) {
109+
$response['success'] = false;
110+
$this->fbeHelper->logException($e);
111+
}
112+
113+
$responseJson = $this->jsonFactory->create();
114+
$responseJson->setData($response);
115+
116+
return $responseJson;
117+
}
118+
}

app/code/Meta/Conversion/view/frontend/templates/pixel/head.phtml

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,21 @@ use Meta\Conversion\Block\Pixel\Head;
88
* @var Escaper $escaper
99
*/
1010

11+
$userDataUrl = $block->getUserDataUrl();
1112
$trackerUrl = $block->getTrackerUrl();
1213
?>
1314
<?php /** @var \Magento\Framework\Escaper $escaper */ ?>
1415
<?php if ($block->getFacebookPixelID()) { ?>
1516
<!-- Meta Business Extension for Magento 2 -->
16-
<!-- Meta Pixel Code -->
17-
<script>
18-
!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
19-
n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
20-
n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
21-
t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
22-
document,'script','//connect.facebook.net/en_US/fbevents.js');
23-
<?php
24-
$dataProcessingOptionsCode = $block->getDataProcessingOptionsJSCode();
25-
if (strlen($dataProcessingOptionsCode) > 0) {
26-
echo $escaper->escapeJs($dataProcessingOptionsCode . "\n");
27-
}
28-
?>
29-
fbq(
30-
'init',
31-
'<?= /* @noEscape */ $block->getFacebookPixelID() ?>',
32-
<?= /* @noEscape */ $block->getPixelInitCode() ?>,
33-
{agent: '<?= /* @noEscape */ $block->getFacebookAgentVersion() ?>' }
34-
);
35-
</script>
3617
<script type="text/x-magento-init">
3718
{
3819
"*": {
20+
"Meta_Conversion/js/initPixel" : {
21+
"pixelId": "<?= $escaper->escapeHtml($block->getFacebookPixelID()); ?>",
22+
"automaticMatchingFlag": <?= /* @noEscape */ $block->getAutomaticMatchingFlag() ? 'true' : 'false'; ?>,
23+
"userDataUrl" : "<?= $escaper->escapeUrl($userDataUrl); ?>",
24+
"agent": "<?= $escaper->escapeHtml($block->getFacebookAgentVersion()); ?>"
25+
},
3926
"Meta_Conversion/js/metaPixelTracker" : {
4027
"url" : "<?= $escaper->escapeUrl($trackerUrl); ?>",
4128
"payload": <?= /* @noEscape */ json_encode([
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/* global fbq */
2+
define([
3+
'jquery'
4+
], function ($) {
5+
'use strict';
6+
return function (config) {
7+
const pixelId = config.pixelId;
8+
const automaticMatchingFlag = config.automaticMatchingFlag;
9+
const userDataUrl = config.userDataUrl;
10+
const agent = config.agent;
11+
const metaPixelInitializedEvent = new Event('metaPixelInitialized');
12+
13+
window.metaPixelInitFlag = false;
14+
15+
if (!window.fbq) {
16+
!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
17+
n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
18+
n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
19+
t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
20+
document,'script','//connect.facebook.net/en_US/fbevents.js');
21+
}
22+
23+
//init pixel with empty user data
24+
fbq(
25+
'init',
26+
pixelId,
27+
{},
28+
{agent: agent}
29+
);
30+
31+
if (!automaticMatchingFlag) {
32+
window.metaPixelInitFlag = true;
33+
window.dispatchEvent(metaPixelInitializedEvent);
34+
return;
35+
}
36+
37+
// update pixel with user data if automatic matching is enabled and user data is available
38+
$.get({
39+
url: userDataUrl,
40+
dataType: 'json',
41+
success: function (res) {
42+
if (res.success && res.user_data) {
43+
fbq(
44+
'init',
45+
pixelId,
46+
res.user_data,
47+
{agent: agent}
48+
);
49+
}
50+
},
51+
error: function (error) {
52+
console.log(error);
53+
}
54+
}).always(function() {
55+
window.metaPixelInitFlag = true;
56+
window.dispatchEvent(metaPixelInitializedEvent);
57+
});
58+
};
59+
});

app/code/Meta/Conversion/view/frontend/web/js/metaPixelTracker.js

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,33 +21,46 @@ define([
2121
}).join('');
2222
}
2323

24-
return function (config) {
25-
const browserEventData = config.browserEventData,
26-
eventId = generateUUID();
27-
28-
config.payload.eventId = eventId;
29-
30-
let browserPayload = config.browserEventData.payload;
24+
function trackPixelEvent(config) {
25+
const pixelId = config.browserEventData.fbPixelId,
26+
agent = config.browserEventData.fbAgentVersion,
27+
track = config.browserEventData.track,
28+
event = config.browserEventData.event,
29+
pixelEventPayload = config.browserEventData.payload,
30+
eventId = config.payload.eventId,
31+
trackServerEventUrl = config.url,
32+
serverEventPayload = config.payload;
3133

32-
browserPayload.source = browserEventData.source;
33-
34-
browserPayload.pluginVersion = browserEventData.pluginVersion;
35-
36-
fbq('set', 'agent', browserEventData.fbAgentVersion, browserEventData.fbPixelId);
37-
fbq(browserEventData.track, browserEventData.event, browserPayload, {
34+
fbq('set', 'agent', agent, pixelId);
35+
fbq(track, event, pixelEventPayload, {
3836
eventID: eventId
3937
});
40-
38+
// trigger server-side CAPI event
4139
$.ajax({
4240
showLoader: true,
43-
url: config.url,
41+
url: trackServerEventUrl,
4442
type: 'POST',
45-
data: config.payload,
43+
data: serverEventPayload,
4644
dataType: 'json',
4745
global: false,
4846
error: function (error) {
4947
console.log(error);
5048
}
5149
});
50+
}
51+
52+
return function (config) {
53+
config.payload.eventId = generateUUID();
54+
config.browserEventData.payload.source = config.browserEventData.source;
55+
config.browserEventData.payload.pluginVersion = config.browserEventData.pluginVersion;
56+
57+
if (window.metaPixelInitFlag) {
58+
trackPixelEvent(config);
59+
} else {
60+
// wait until pixel is initialized
61+
window.addEventListener('metaPixelInitialized', () => {
62+
trackPixelEvent(config);
63+
}, {once: true});
64+
}
5265
};
5366
});

0 commit comments

Comments
 (0)