Facebook for WooCommerce - Version 1.9.15

Version Description

  • 2019-06-27 =
  • CSRF handling for Ajax calls like ajax_woo_infobanner_post_click, ajax_woo_infobanner_post_xout, ajax_fb_toggle_visibility
  • use phpcs to adhere to WP coding standards
  • Minor UI changes on the iFrame
Download this release

Release Info

Developer facebook4woocommerce
Plugin Icon Facebook for WooCommerce
Version 1.9.15
Comparing to
See all releases

Code changes from version 1.9.14 to 1.9.15

assets/css/facebook.css CHANGED
@@ -42,16 +42,16 @@
42
}
43
44
#fbsetup .loader {
45
- border: 4px solid #f3f3f3; /* Light grey */
46
- border-top: 4px solid #3498db; /* Blue */
47
- border-radius: 50%;
48
- width: 20px;
49
- height: 20px;
50
- animation: spin 2s linear infinite;
51
}
52
@keyframes spin {
53
- 0% { transform: rotate(0deg); }
54
- 100% { transform: rotate(360deg); }
55
}
56
57
#fbsetup .btn {
@@ -199,7 +199,7 @@
199
.tooltip {
200
position: relative;
201
border-bottom: 1px dotted black;
202
- /* container: */
203
border: 1px solid;
204
border-radius: 2px;
205
/* Launch Test: */
42
}
43
44
#fbsetup .loader {
45
+ border: 4px solid #f3f3f3; /* Light grey */
46
+ border-top: 4px solid #3498db; /* Blue */
47
+ border-radius: 50%;
48
+ width: 20px;
49
+ height: 20px;
50
+ animation: spin 2s linear infinite;
51
}
52
@keyframes spin {
53
+ 0% { transform: rotate(0deg); }
54
+ 100% { transform: rotate(360deg); }
55
}
56
57
#fbsetup .btn {
199
.tooltip {
200
position: relative;
201
border-bottom: 1px dotted black;
202
+ /* container: */
203
border: 1px solid;
204
border-radius: 2px;
205
/* Launch Test: */
assets/js/facebook-infobanner.js CHANGED
@@ -11,32 +11,45 @@
11
* Takes optional payload for POST and optional callback.
12
*/
13
function ajax(action, payload = null, callback = null, failcallback = null) {
14
- var data = {
15
- 'action': action,
16
- };
17
- if (payload){
18
- for (var attrname in payload) { data[attrname] = payload[attrname]; }
19
- }
20
21
- // Since Wordpress 2.8 ajaxurl is always defined in admin header and
22
- // points to admin-ajax.php
23
- jQuery.post(ajaxurl, data, function(response) {
24
- if(callback) {
25
- callback(response);
26
- }
27
- }).fail(function(errorResponse){
28
- if(failcallback) {
29
- failcallback(errorResponse);
30
- }
31
- });
32
}
33
34
function fb_woo_infobanner_post_click(){
35
- console.log("Woo infobanner post tip click!");
36
- return ajax('ajax_woo_infobanner_post_click');
37
}
38
39
function fb_woo_infobanner_post_xout() {
40
- console.log("Woo infobanner post tip xout!");
41
- return ajax('ajax_woo_infobanner_post_xout');
42
}
11
* Takes optional payload for POST and optional callback.
12
*/
13
function ajax(action, payload = null, callback = null, failcallback = null) {
14
+ var data = Object.assign( {}, {
15
+ 'action': action,
16
+ }, payload );
17
18
+ // Since Wordpress 2.8 ajaxurl is always defined in admin header and
19
+ // points to admin-ajax.php
20
+ jQuery.post(
21
+ ajaxurl,
22
+ data,
23
+ function(response) {
24
+ if (callback) {
25
+ callback( response );
26
+ }
27
+ }
28
+ ).fail(
29
+ function(errorResponse){
30
+ if (failcallback) {
31
+ failcallback( errorResponse );
32
+ }
33
+ }
34
+ );
35
}
36
37
function fb_woo_infobanner_post_click(){
38
+ console.log( "Woo infobanner post tip click!" );
39
+ return ajax(
40
+ 'ajax_woo_infobanner_post_click',
41
+ {
42
+ "_ajax_nonce": wc_facebook_infobanner_jsx.nonce
43
+ },
44
+ );
45
}
46
47
function fb_woo_infobanner_post_xout() {
48
+ console.log( "Woo infobanner post tip xout!" );
49
+ return ajax(
50
+ 'ajax_woo_infobanner_post_xout',
51
+ {
52
+ "_ajax_nonce": wc_facebook_infobanner_jsx.nonce
53
+ },
54
+ );
55
}
assets/js/facebook-metabox.js CHANGED
@@ -12,56 +12,69 @@
12
* Takes optional payload for POST and optional callback.
13
*/
14
function ajax(action, payload = null, cb = null, failcb = null) {
15
- var data = {
16
- 'action': action,
17
- };
18
- if (payload){
19
- for (var attrname in payload) { data[attrname] = payload[attrname]; }
20
- }
21
22
- // Since Wordpress 2.8 ajaxurl is always defined in admin header and
23
- // points to admin-ajax.php
24
- jQuery.post(ajaxurl, data, function(response) {
25
- if(cb) {
26
- cb(response);
27
- }
28
- }).fail(function(errorResponse){
29
- if(failcb) {
30
- failcb(errorResponse);
31
- }
32
- });
33
}
34
35
function fb_reset_product(wp_id) {
36
- if(confirm('Resetting Facebook metadata will not remove this product from your shop. ' +
37
- 'If you have duplicated another product and are trying to publish a new Facebook product, ' +
38
- 'click OK to proceed. ' +
39
- 'Otherwise, Facebook metadata will be restored when this product is updated again.')) {
40
- var metadata = document.querySelector('#fb_metadata');
41
- if(metadata) {
42
- metadata.innerHTML =
43
- "<b>This product is not yet synced to Facebook.</b>";
44
- }
45
- return ajax(
46
- 'ajax_reset_single_fb_product',
47
- {'wp_id': wp_id}
48
- );
49
- }
50
}
51
52
function fb_delete_product(wp_id) {
53
- if(confirm('Are you sure you want to delete this product on Facebook? If you only want to "hide" the product, '+
54
- 'uncheck the "Visible" checkbox and hit "Update". If you delete a product on Facebook and hit "Update" after, ' +
55
- 'this product will be recreated. To permanently remove this product from Facebook, hit "OK" and close the window.'+
56
- 'This will not delete the product from WooCommerce.')) {
57
- var metadata = document.querySelector('#fb_metadata');
58
- if(metadata) {
59
- metadata.innerHTML =
60
- "<b>This product is not yet synced to Facebook.</b>";
61
- }
62
- return ajax(
63
- 'ajax_delete_fb_product',
64
- {'wp_id': wp_id}
65
- );
66
- }
67
}
12
* Takes optional payload for POST and optional callback.
13
*/
14
function ajax(action, payload = null, cb = null, failcb = null) {
15
+ var data = Object.assign( {}, {
16
+ 'action': action,
17
+ }, payload);
18
19
+ // Since Wordpress 2.8 ajaxurl is always defined in admin header and
20
+ // points to admin-ajax.php
21
+ jQuery.post(
22
+ ajaxurl,
23
+ data,
24
+ function(response) {
25
+ if (cb) {
26
+ cb( response );
27
+ }
28
+ }
29
+ ).fail(
30
+ function(errorResponse){
31
+ if (failcb) {
32
+ failcb( errorResponse );
33
+ }
34
+ }
35
+ );
36
}
37
38
function fb_reset_product(wp_id) {
39
+ if (confirm(
40
+ 'Resetting Facebook metadata will not remove this product from your shop. ' +
41
+ 'If you have duplicated another product and are trying to publish a new Facebook product, ' +
42
+ 'click OK to proceed. ' +
43
+ 'Otherwise, Facebook metadata will be restored when this product is updated again.'
44
+ )) {
45
+ var metadata = document.querySelector( '#fb_metadata' );
46
+ if (metadata) {
47
+ metadata.innerHTML =
48
+ "<b>This product is not yet synced to Facebook.</b>";
49
+ }
50
+ return ajax(
51
+ 'ajax_reset_single_fb_product',
52
+ {
53
+ 'wp_id': wp_id,
54
+ "_ajax_nonce": wc_facebook_metabox_jsx.nonce
55
+ }
56
+ );
57
+ }
58
}
59
60
function fb_delete_product(wp_id) {
61
+ if (confirm(
62
+ 'Are you sure you want to delete this product on Facebook? If you only want to "hide" the product, ' +
63
+ 'uncheck the "Visible" checkbox and hit "Update". If you delete a product on Facebook and hit "Update" after, ' +
64
+ 'this product will be recreated. To permanently remove this product from Facebook, hit "OK" and close the window.' +
65
+ 'This will not delete the product from WooCommerce.'
66
+ )) {
67
+ var metadata = document.querySelector( '#fb_metadata' );
68
+ if (metadata) {
69
+ metadata.innerHTML =
70
+ "<b>This product is not yet synced to Facebook.</b>";
71
+ }
72
+ return ajax(
73
+ 'ajax_delete_fb_product',
74
+ {
75
+ 'wp_id': wp_id,
76
+ "_ajax_nonce": wc_facebook_metabox_jsx.nonce,
77
+ }
78
+ );
79
+ }
80
}
assets/js/facebook-products.js CHANGED
@@ -12,58 +12,73 @@
12
* Takes optional payload for POST and optional callback.
13
*/
14
function ajax(action, payload = null, cb = null, failcb = null) {
15
- var data = {
16
- 'action': action,
17
- };
18
- if (payload){
19
- for (var attrname in payload) { data[attrname] = payload[attrname]; }
20
- }
21
22
- // Since Wordpress 2.8 ajaxurl is always defined in admin header and
23
- // points to admin-ajax.php
24
- jQuery.post(ajaxurl, data, function(response) {
25
- if(cb) {
26
- cb(response);
27
- }
28
- }).fail(function(errorResponse){
29
- if(failcb) {
30
- failcb(errorResponse);
31
- }
32
- });
33
}
34
35
function fb_toggle_visibility(wp_id, published) {
36
- var buttonId = document.querySelector("#viz_" + wp_id);
37
- var tooltip = document.querySelector("#tip_" + wp_id);
38
39
- if(published){
40
- tooltip.setAttribute('data-tip',
41
- 'Product is synced and published (visible) on Facebook.'
42
- );
43
- buttonId.setAttribute('onclick','fb_toggle_visibility('+wp_id+', false)');
44
- buttonId.innerHTML = 'Hide';
45
- buttonId.setAttribute('class', 'button');
46
- } else {
47
- tooltip.setAttribute('data-tip',
48
- 'Product is synced but not marked as published (visible) on Facebook.'
49
- );
50
- buttonId.setAttribute('onclick','fb_toggle_visibility('+wp_id+', true)');
51
- buttonId.innerHTML = 'Show';
52
- buttonId.setAttribute('class', 'button button-primary button-large');
53
- }
54
55
- //Reset tooltip
56
- jQuery(function($) {
57
- $('.tips').tipTip({
58
- 'attribute': 'data-tip',
59
- 'fadeIn': 50,
60
- 'fadeOut': 50,
61
- 'delay': 200
62
- });
63
- });
64
65
- return ajax(
66
- 'ajax_fb_toggle_visibility',
67
- {'wp_id': wp_id, 'published': published}
68
- );
69
}
12
* Takes optional payload for POST and optional callback.
13
*/
14
function ajax(action, payload = null, cb = null, failcb = null) {
15
+ var data = Object.assign( {},
16
+ {
17
+ 'action': action,
18
+ }, payload
19
+ );
20
21
+ // Since Wordpress 2.8 ajaxurl is always defined in admin header and
22
+ // points to admin-ajax.php
23
+ jQuery.post(
24
+ ajaxurl,
25
+ data,
26
+ function(response) {
27
+ if (cb) {
28
+ cb( response );
29
+ }
30
+ }
31
+ ).fail(
32
+ function(errorResponse){
33
+ if (failcb) {
34
+ failcb( errorResponse );
35
+ }
36
+ }
37
+ );
38
}
39
40
function fb_toggle_visibility(wp_id, published) {
41
+ var buttonId = document.querySelector( "#viz_" + wp_id );
42
+ var tooltip = document.querySelector( "#tip_" + wp_id );
43
44
+ if (published) {
45
+ tooltip.setAttribute(
46
+ 'data-tip',
47
+ 'Product is synced and published (visible) on Facebook.'
48
+ );
49
+ buttonId.setAttribute( 'onclick','fb_toggle_visibility(' + wp_id + ', false)' );
50
+ buttonId.innerHTML = 'Hide';
51
+ buttonId.setAttribute( 'class', 'button' );
52
+ } else {
53
+ tooltip.setAttribute(
54
+ 'data-tip',
55
+ 'Product is synced but not marked as published (visible) on Facebook.'
56
+ );
57
+ buttonId.setAttribute( 'onclick','fb_toggle_visibility(' + wp_id + ', true)' );
58
+ buttonId.innerHTML = 'Show';
59
+ buttonId.setAttribute( 'class', 'button button-primary button-large' );
60
+ }
61
62
+ // Reset tooltip
63
+ jQuery(
64
+ function($) {
65
+ $( '.tips' ).tipTip(
66
+ {
67
+ 'attribute': 'data-tip',
68
+ 'fadeIn': 50,
69
+ 'fadeOut': 50,
70
+ 'delay': 200
71
+ }
72
+ );
73
+ }
74
+ );
75
76
+ return ajax(
77
+ 'ajax_fb_toggle_visibility',
78
+ {
79
+ 'wp_id': wp_id,
80
+ 'published': published,
81
+ "_ajax_nonce": wc_facebook_product_jsx.nonce
82
+ }
83
+ );
84
}
assets/js/facebook-settings.js CHANGED
@@ -8,200 +8,230 @@
8
*/
9
10
var fb_sync_no_response_count = 0;
11
- var fb_show_advanced_options = false;
12
13
function toggleAdvancedOptions() {
14
- var opts = document.getElementById("fbAdvancedOptions");
15
- if (!fb_show_advanced_options) {
16
- opts.style.display = "block";
17
- document.getElementById('fbAdvancedOptionsText').innerHTML = 'Hide Advanced Settings';
18
- } else {
19
- opts.style.display = "none";
20
- document.getElementById('fbAdvancedOptionsText').innerHTML = 'Show Advanced Settings';
21
- }
22
- fb_show_advanced_options = !fb_show_advanced_options;
23
}
24
25
function openPopup() {
26
- var width = 1153;
27
- var height = 808;
28
- var topPos = screen.height / 2 - height / 2;
29
- var leftPos = screen.width / 2 - width / 2;
30
- window.originParam = window.location.protocol + '//' + window.location.host;
31
- var popupUrl;
32
- if(window.facebookAdsToolboxConfig.popupOrigin.includes('staticxx')) {
33
- window.facebookAdsToolboxConfig.popupOrigin = 'https://www.facebook.com/';
34
- }
35
- window.facebookAdsToolboxConfig.popupOrigin = prepend_protocol(
36
- window.facebookAdsToolboxConfig.popupOrigin
37
- );
38
- popupUrl = window.facebookAdsToolboxConfig.popupOrigin;
39
-
40
- var path = '/ads/dia';
41
- var page = window.open(popupUrl + '/login.php?display=popup&next=' + encodeURIComponent(popupUrl + path + '?origin=' + window.originParam + ' &merchant_settings_id=' + window.facebookAdsToolboxConfig.diaSettingId), 'DiaWizard', ['toolbar=no', 'location=no', 'directories=no', 'status=no', 'menubar=no', 'scrollbars=no', 'resizable=no', 'copyhistory=no', 'width=' + width, 'height=' + height, 'top=' + topPos, 'left=' + leftPos].join(','));
42
-
43
- return function (type, params) {
44
- page.postMessage({
45
- type: type,
46
- params: params
47
- }, window.facebookAdsToolboxConfig.popupOrigin);
48
- };
49
}
50
51
function prepend_protocol(url) {
52
- // Preprend https if the url begis with //www.
53
- if (url.indexOf('//www.') === 0) {
54
- url = 'https:' + url;
55
- }
56
- return url;
57
}
58
59
function get_product_catalog_id_box() {
60
- return document.querySelector('#woocommerce_facebookcommerce_fb_product_catalog_id') || null;
61
}
62
function get_pixel_id_box() {
63
- return document.querySelector('#woocommerce_facebookcommerce_fb_pixel_id') || null;
64
}
65
function get_pixel_use_pii_id_box() {
66
- return document.querySelector('#woocommerce_facebookcommerce_fb_pixel_use_pii') || null;
67
}
68
function get_api_key_box() {
69
- return document.querySelector('#woocommerce_facebookcommerce_fb_api_key') || null;
70
}
71
function get_page_id_box() {
72
- return document.querySelector('#woocommerce_facebookcommerce_fb_page_id') || null;
73
}
74
function get_ems_id_box() {
75
- return document.querySelector('#woocommerce_facebookcommerce_fb_external_merchant_settings_id') || null;
76
}
77
78
/*
79
* Ajax helper function.
80
* Takes optional payload for POST and optional callback.
81
*/
82
- function ajax(action, payload = null, callback = null, failcallback = null) {
83
- var data = Object.assign( {}, {
84
- 'action': action,
85
- }, payload);
86
-
87
- // Since Wordpress 2.8 ajaxurl is always defined in admin header and
88
- // points to admin-ajax.php
89
- jQuery.post(ajaxurl, data, function(response) {
90
- if(callback) {
91
- callback(response);
92
- }
93
- }).fail(function(errorResponse){
94
- if(failcallback) {
95
- failcallback(errorResponse);
96
- }
97
- });
98
- }
99
-
100
- var settings = {'facebook_for_woocommerce' : 1};
101
var pixel_settings = {'facebook_for_woocommerce' : 1};
102
103
function facebookConfig() {
104
- window.sendToFacebook = openPopup();
105
- window.diaConfig = { 'clientSetup': window.facebookAdsToolboxConfig };
106
}
107
108
function fb_flush(){
109
- console.log("Removing all FBIDs from all products!");
110
- return ajax('ajax_reset_all_fb_products');
111
}
112
113
function sync_confirm(verbose = null) {
114
- var msg = '';
115
- switch (verbose) {
116
- case 'fb_force_resync':
117
- msg = 'Your products will now be resynced with Facebook, ' +
118
- 'this may take some time.';
119
- break;
120
- case 'fb_test_product_sync':
121
- msg = 'Launch Test?';
122
- break;
123
- default:
124
- msg = 'Facebook for WooCommerce automatically syncs your products on ' +
125
- 'create/update. Are you sure you want to force product resync? ' +
126
- 'This will query all published products and may take some time. ' +
127
- 'You only need to do this if your products are out of sync ' +
128
- 'or some of your products did not sync.';
129
- }
130
- if(confirm(msg)) {
131
- sync_all_products(
132
- window.facebookAdsToolboxConfig.feed.hasClientSideFeedUpload,
133
- verbose == 'fb_test_product_sync'
134
- );
135
- window.fb_sync_start_time = new Date().getTime();
136
- }
137
}
138
139
// Launch the confirm dialog immediately if the param is in the URL.
140
- if (window.location.href.includes("fb_force_resync")) {
141
- window.onload = function() { sync_confirm("fb_force_resync"); };
142
- } else if (window.location.href.includes("fb_test_product_sync")) {
143
- // Test products sync by feed.
144
- window.is_test = true;
145
- window.onload = function() { sync_confirm("fb_test_product_sync"); };
146
}
147
148
function sync_all_products($using_feed = false, $is_test = false) {
149
- if (get_product_catalog_id_box() && !get_product_catalog_id_box().value){
150
- return;
151
- }
152
- if (get_api_key_box() && !get_api_key_box().value){
153
- return;
154
- }
155
- console.log('Syncing all products!');
156
- window.fb_connected = true;
157
- sync_in_progress();
158
- if ($using_feed) {
159
- window.facebookAdsToolboxConfig.feed.hasClientSideFeedUpload = true;
160
- window.feed_upload = true;
161
- ping_feed_status_queue();
162
- return $is_test ? ajax('ajax_test_sync_products_using_feed')
163
- : ajax('ajax_sync_all_fb_products_using_feed');
164
- } else {
165
- return ajax('ajax_sync_all_fb_products');
166
- }
167
}
168
169
// Reset all state
170
function delete_all_settings(callback = null, failcallback = null) {
171
- if (get_product_catalog_id_box()) {
172
- get_product_catalog_id_box().value = '';
173
- }
174
- if(get_pixel_id_box()) {
175
- get_pixel_id_box().value = '';
176
- }
177
- if(get_pixel_use_pii_id_box()) {
178
- get_pixel_use_pii_id_box().checked = false;
179
- }
180
- if(get_api_key_box()) {
181
- get_api_key_box().value = '';
182
- }
183
- if(get_page_id_box()) {
184
- get_page_id_box().value = '';
185
- }
186
- if(get_ems_id_box()) {
187
- get_ems_id_box().value = '';
188
- }
189
-
190
- window.facebookAdsToolboxConfig.pixel.pixelId = '';
191
- window.facebookAdsToolboxConfig.diaSettingId = '';
192
-
193
- reset_buttons();
194
- window.fb_connected = false;
195
-
196
- console.log('Deleting all settings and removing all FBIDs!');
197
- return ajax(
198
- 'ajax_delete_fb_settings',
199
- {
200
- "_ajax_nonce": wc_facebook_settings_jsx.nonce,
201
- },
202
- callback,
203
- failcallback
204
- );
205
}
206
207
// save_settings and save_settings_and_sync should only be called once
@@ -211,690 +241,744 @@ function delete_all_settings(callback = null, failcallback = null) {
211
// It's also called again if the pixel id is ever changed or pixel pii is
212
// enabled or disabled.
213
function save_settings(callback = null, failcallback = null, localsettings = null){
214
- if (!localsettings) {
215
- localsettings = settings;
216
- }
217
- ajax('ajax_save_fb_settings', localsettings,
218
- function(response){
219
- if(callback) {
220
- callback(response);
221
- }
222
- },
223
- function(errorResponse){
224
- if(failcallback) {
225
- failcallback(errorResponse);
226
- }
227
- }
228
- );
229
}
230
231
// save_settings wrapper for plugins as we do not need to:
232
- // 1. sync products again after plugin is configured
233
- // 2. check api_key, which is from facebook and is only necessary
234
- // for following sync products
235
function save_settings_for_plugin(callback, failcallback) {
236
- save_settings(
237
- function(response){
238
- if (response && response.includes('settings_saved')){
239
- console.log(response);
240
- callback(response);
241
- } else {
242
- console.log('Fail response on save_settings_and_sync');
243
- failcallback(response);
244
- }
245
- },
246
- function(errorResponse){
247
- console.log('Ajax error while saving settings:' + JSON.stringify(errorResponse));
248
- failcallback(errorResponse);
249
- });
250
}
251
252
// see comments in save_settings function above
253
function save_settings_and_sync(message) {
254
- if ('api_key' in settings){
255
- save_settings(
256
- function(response){
257
- if (response && response.includes('settings_saved')){
258
- console.log(response);
259
- //Final acks
260
- window.sendToFacebook('ack set pixel', message.params);
261
- window.sendToFacebook('ack set page access token', message.params);
262
- window.sendToFacebook('ack set merchant settings', message.params);
263
- sync_all_products(true);
264
- } else {
265
- window.sendToFacebook('fail save_settings', response);
266
- console.log('Fail response on save_settings_and_sync');
267
- }
268
- },
269
- function(errorResponse){
270
- console.log('Ajax error while saving settings:' + JSON.stringify(errorResponse));
271
- window.sendToFacebook('fail save_settings_ajax', JSON.stringify(errorResponse));
272
- }
273
- );
274
- }
275
- }
276
-
277
- //Reset buttons to brand new setup state
278
function reset_buttons(){
279
- if(document.querySelector('#settings')){
280
- document.querySelector('#settings').style.display = 'none';
281
- }
282
- if(document.querySelector('#cta_button')){
283
- var cta_element = document.querySelector('#cta_button');
284
- cta_element.innerHTML = 'Get Started';
285
- cta_element.style['font-size'] = '13px';
286
- cta_element.style.width = '80px';
287
- cta_element.href = '#';
288
- cta_element.onclick= function() { facebookConfig(); };
289
- }
290
- if(document.querySelector('#learnmore_button')){
291
- document.querySelector('#learnmore_button').style.display = 'none';
292
- }
293
- if(document.querySelector('#setup_h1')) {
294
- document.querySelector('#setup_h1').innerHTML =
295
- 'Grow your business on Facebook';
296
- }
297
- if(document.querySelector('#setup_l1')){
298
- document.querySelector('#setup_l1').innerHTML =
299
- 'Easily install a tracking pixel';
300
- }
301
- if(document.querySelector('#setup_l2')){
302
- document.querySelector('#setup_l2').innerHTML =
303
- 'Upload your products and create a shop';
304
- }
305
- if(document.querySelector('#setup_l3')){
306
- document.querySelector('#setup_l3').innerHTML =
307
- 'Create dynamic ads with your products and pixel';
308
- }
309
- }
310
-
311
- //Remove reset/settings buttons during product sync
312
function sync_in_progress(){
313
- if(document.querySelector('#settings')){
314
- document.querySelector('#settings').style.display = '';
315
- }
316
- if(document.querySelector('#connection_status')){
317
- document.querySelector('#connection_status').style.display = '';
318
- }
319
- if(document.querySelector('#sync_complete')){
320
- document.querySelector('#sync_complete').style.display = 'none';
321
- }
322
- //Get rid of all the buttons
323
- if(document.querySelector('#setting_button')){
324
- document.querySelector('#setting_button').style['pointer-events'] = 'none';
325
- }
326
- if(document.querySelector('#resync_products')) {
327
- document.querySelector('#resync_products').style['pointer-events'] = 'none';
328
- }
329
- if(document.querySelector('#test_product_sync')) {
330
- document.querySelector('#test_product_sync').style.display = 'none';
331
- }
332
- //Set a product sync status
333
- if(document.querySelector('#sync_progress')){
334
- document.querySelector('#sync_progress').innerHTML =
335
- 'Syncing... Keep this browser open <br/>' +
336
- 'Until sync is complete<br/>' +
337
- '<div class="loader"></div>';
338
- }
339
}
340
341
function sync_not_in_progress(){
342
- // Reset to pre-setup state.
343
- if(document.querySelector('#cta_button')){
344
- var cta_element = document.querySelector('#cta_button');
345
- cta_element.innerHTML = 'Create Ad';
346
- cta_element.style['font-size'] = '12px';
347
- cta_element.style.width = '60px';
348
- if (window.facebookAdsToolboxConfig.diaSettingId) {
349
- cta_element.onclick= function() {
350
- window.open('https://www.facebook.com/ads/dia/redirect/?settings_id=' +
351
- window.facebookAdsToolboxConfig.diaSettingId + '&version=2' +
352
- '&entry_point=admin_panel');
353
- };
354
- } else {
355
- cta_element.style['pointer-events'] = 'none';
356
- }
357
- }
358
- if(document.querySelector('#learnmore_button')){
359
- var learnmore_element = document.querySelector('#learnmore_button');
360
- if (window.facebookAdsToolboxConfig.diaSettingId) {
361
- learnmore_element.style.display = '';
362
- }
363
- }
364
- if(document.querySelector('#setup_h1')) {
365
- document.querySelector('#setup_h1').innerHTML =
366
- 'Reach the right people and sell more products';
367
- }
368
- if(document.querySelector('#setup_l1')){
369
- document.querySelector('#setup_l1').innerHTML =
370
- 'Create an ad in a few steps';
371
- }
372
- if(document.querySelector('#setup_l2')){
373
- document.querySelector('#setup_l2').innerHTML =
374
- 'Use built-in best practice for online sales';
375
- }
376
- if(document.querySelector('#setup_l3')){
377
- document.querySelector('#setup_l3').innerHTML =
378
- 'Get reporting on sales and revenue';
379
- }
380
- if(document.querySelector('#settings')){
381
- document.querySelector('#settings').style.display = '';
382
- }
383
- // Enable buttons.
384
- if(document.querySelector('#setting_button')){
385
- document.querySelector('#setting_button').style['pointer-events'] = 'auto';
386
- }
387
- if(document.querySelector('#resync_products')) {
388
- document.querySelector('#resync_products').style ['pointer-events'] = 'auto';
389
- }
390
- // Remove sync progress.
391
- if(document.querySelector('#sync_progress')){
392
- document.querySelector('#sync_progress').innerHTML = '';
393
- }
394
}
395
396
function not_connected(){
397
- if(document.querySelector('#connection_status')){
398
- document.querySelector('#connection_status').style.display = 'none';
399
- }
400
-
401
- if(document.querySelector('#setting_button')){
402
- document.querySelector('#setting_button').style['pointer-events'] = 'auto';
403
- }
404
- if(document.querySelector('#resync_products')) {
405
- document.querySelector('#resync_products').style['pointer-events'] = 'none';
406
- }
407
- if(document.querySelector('#sync_complete')) {
408
- document.querySelector('#sync_complete').style.display = 'none';
409
- }
410
- if(document.querySelector('#sync_progress')){
411
- document.querySelector('#sync_progress').innerHTML = '';
412
- }
413
}
414
415
function addAnEventListener(obj,evt,func) {
416
- if ('addEventListener' in obj){
417
- obj.addEventListener(evt,func, false);
418
- } else if ('attachEvent' in obj){//IE
419
- obj.attachEvent('on'+evt,func);
420
- }
421
}
422
423
function setMerchantSettings(message) {
424
- if (!message.params.setting_id) {
425
- console.error('Facebook Extension Error: got no setting_id', message.params);
426
- window.sendToFacebook('fail set merchant settings', message.params);
427
- return;
428
- }
429
- if(get_ems_id_box()){
430
- get_ems_id_box().value = message.params.setting_id;
431
- }
432
433
- settings.external_merchant_settings_id = message.params.setting_id;
434
435
- //Immediately set in case button is clicked again
436
- window.facebookAdsToolboxConfig.diaSettingId = message.params.setting_id;
437
- //Ack merchant settings happens after settings are saved
438
}
439
440
function setCatalog(message) {
441
- if (!message.params.catalog_id) {
442
- console.error('Facebook Extension Error: got no catalog_id', message.params);
443
- window.sendToFacebook('fail set catalog', message.params);
444
- return;
445
- }
446
- if(get_api_key_box()){
447
- get_product_catalog_id_box().value = message.params.catalog_id;
448
- }
449
450
- settings.product_catalog_id = message.params.catalog_id;
451
452
- window.sendToFacebook('ack set catalog', message.params);
453
}
454
455
456
function setPixel(message) {
457
- if (!message.params.pixel_id) {
458
- console.error('Facebook Ads Extension Error: got no pixel_id', message.params);
459
- window.sendToFacebook('fail set pixel', message.params);
460
- return;
461
- }
462
- if(get_pixel_id_box()){
463
- get_pixel_id_box().value = message.params.pixel_id;
464
- }
465
-
466
- settings.pixel_id = message.params.pixel_id;
467
- pixel_settings.pixel_id = settings.pixel_id;
468
- if (message.params.pixel_use_pii !== undefined) {
469
- if(get_pixel_use_pii_id_box()){
470
- //!! will explicitly convert truthy/falsy values to a boolean
471
- get_pixel_use_pii_id_box().checked = !!message.params.pixel_use_pii;
472
- }
473
- settings.pixel_use_pii = message.params.pixel_use_pii;
474
- pixel_settings.pixel_use_pii = settings.pixel_use_pii;
475
- }
476
-
477
- // We need this to support changing the pixel id after setup.
478
- save_settings(
479
- function(response){
480
- if (response && response.includes('settings_saved')){
481
- window.sendToFacebook('ack set pixel', message.params);
482
- } //may not get settings_saved if we try to save pixel before an API key
483
- },
484
- function(errorResponse){
485
- console.log(errorResponse);
486
- window.sendToFacebook('fail set pixel', errorResponse);
487
- },
488
- pixel_settings
489
- );
490
}
491
492
function genFeed(message) {
493
- //no-op
494
}
495
496
function setAccessTokenAndPageId(message) {
497
- if (!message.params.page_token) {
498
- console.error('Facebook Ads Extension Error: got no page_token',
499
- message.params);
500
- window.sendToFacebook('fail set page access token', message.params);
501
- return;
502
- }
503
- /*
504
- Set page_token here
505
- */
506
-
507
- if(get_api_key_box()){
508
- get_api_key_box().value = message.params.page_token;
509
- }
510
-
511
- if(get_page_id_box()){
512
- get_page_id_box().value = message.params.page_id;
513
- }
514
-
515
- settings.api_key = message.params.page_token;
516
- settings.page_id = message.params.page_id;
517
- //Ack token in "save_settings_and_sync" for final ack
518
-
519
- window.facebookAdsToolboxConfig.tokenExpired = false;
520
- if(document.querySelector('#token_text')){
521
- document.querySelector('#token_text').innerHTML =
522
- `<strong>Your API key has been updated.<br />
523
- Please refresh the page.</strong>`;
524
- }
525
}
526
527
function setMsgerChatSetup(data) {
528
- if (data.hasOwnProperty('is_messenger_chat_plugin_enabled')) {
529
- settings.is_messenger_chat_plugin_enabled =
530
- data.is_messenger_chat_plugin_enabled;
531
- }
532
- if (data.hasOwnProperty('facebook_jssdk_version')) {
533
- settings.facebook_jssdk_version =
534
- data.facebook_jssdk_version;
535
- }
536
- if (data.hasOwnProperty('page_id')) {
537
- settings.fb_page_id = data.page_id;
538
- }
539
-
540
- if (data.hasOwnProperty('customization')) {
541
- var customization = data.customization;
542
-
543
- if (customization.hasOwnProperty('greetingTextCode')) {
544
- settings.msger_chat_customization_greeting_text_code =
545
- customization.greetingTextCode;
546
- }
547
- if (customization.hasOwnProperty('locale')) {
548
- settings.msger_chat_customization_locale =
549
- customization.locale;
550
- }
551
- if (customization.hasOwnProperty('themeColorCode')) {
552
- settings.msger_chat_customization_theme_color_code =
553
- customization.themeColorCode;
554
- }
555
- }
556
}
557
558
function iFrameListener(event) {
559
- // Fix for web.facebook.com
560
- const origin = event.origin || event.originalEvent.origin;
561
- if (origin != window.facebookAdsToolboxConfig.popupOrigin &&
562
- urlFromSameDomain(origin, window.facebookAdsToolboxConfig.popupOrigin)) {
563
- window.facebookAdsToolboxConfig.popupOrigin = origin;
564
- }
565
-
566
- switch (event.data.type) {
567
- case 'reset':
568
- delete_all_settings(function(res){
569
- if(res && event.data.params) {
570
- if(res === 'Settings Deleted'){
571
- window.sendToFacebook('ack reset', event.data.params);
572
- }else{
573
- console.log(res);
574
- alert(res);
575
- }
576
- }else {
577
- console.log("Got no response from delete_all_settings");
578
- }
579
- },function(err){
580
- console.error(err);
581
- });
582
- break;
583
- case 'get dia settings':
584
- window.sendToFacebook('dia settings', window.diaConfig);
585
- break;
586
- case 'set merchant settings':
587
- setMerchantSettings(event.data);
588
- break;
589
- case 'set catalog':
590
- setCatalog(event.data);
591
- break;
592
- case 'set pixel':
593
- setPixel(event.data);
594
- break;
595
- case 'gen feed':
596
- genFeed();
597
- break;
598
- case 'set page access token':
599
- //Should be last message received
600
- setAccessTokenAndPageId(event.data);
601
- save_settings_and_sync(event.data);
602
- break;
603
- case 'set msger chat':
604
- setMsgerChatSetup(event.data.params);
605
- save_settings_for_plugin(
606
- function(response) {
607
- window.sendToFacebook('ack msger chat', event.data);
608
- },
609
- function(response) {
610
- window.sendToFacebook('fail ack msger chat', event.data);
611
- });
612
- break;
613
- }
614
- }
615
-
616
- addAnEventListener(window,'message',iFrameListener);
617
618
function urlFromSameDomain(url1, url2) {
619
- if (!url1.startsWith('http') || !url2.startsWith('http')) {
620
- return false;
621
- }
622
- var u1 = parseURL(url1);
623
- var u2 = parseURL(url2);
624
- var u1host = u1.host.replace(/^\w+\./, 'www.');
625
- var u2host = u2.host.replace(/^\w+\./, 'www.');
626
- return u1.protocol === u2.protocol && u1host === u2host;
627
}
628
629
function parseURL(url) {
630
- var parser = document.createElement('a');
631
- parser.href = url;
632
- return parser;
633
}
634
635
// Only do pings for supporting older (pre 1.8) setups.
636
window.fb_pings =
637
(window.facebookAdsToolboxConfig.feed.hasClientSideFeedUpload) ?
638
null :
639
- setInterval(function(){
640
- console.log("Pinging queue...");
641
- check_queues();
642
- }, 10000);
643
644
function ping_feed_status_queue(count = 0) {
645
- window.fb_feed_pings = setInterval(function() {
646
- console.log('Pinging feed uploading queue...');
647
- check_feed_upload_queue(count);
648
- }, 30000*(1 << count));
649
- }
650
-
651
- function product_sync_complete(sync_progress_element){
652
- sync_not_in_progress();
653
- if(document.querySelector('#sync_complete')){
654
- document.querySelector('#sync_complete').style.display = '';
655
- }
656
- if(sync_progress_element) {
657
- sync_progress_element.innerHTML = '';
658
- }
659
- clearInterval(window.fb_pings);
660
- }
661
-
662
- function check_queues(){
663
- ajax('ajax_fb_background_check_queue',
664
- {"request_time": new Date().getTime()}, function(response){
665
- if (window.feed_upload) {
666
- clearInterval(window.fb_pings);
667
- return;
668
- }
669
- var sync_progress_element = document.querySelector('#sync_progress');
670
- var res = parse_response_check_connection(response);
671
- if (!res) {
672
- if (fb_sync_no_response_count++ > 5) {
673
- clearInterval(window.fb_pings);
674
- }
675
- return;
676
- }
677
- fb_sync_no_response_count = 0;
678
-
679
- if(res){
680
- if(!res.background){
681
- console.log("No background sync found, disabling pings");
682
- clearInterval(window.fb_pings);
683
- }
684
-
685
- var processing = !!res.processing; //explicit boolean conversion
686
- var remaining = res.remaining;
687
- if(processing) {
688
- if(sync_progress_element) {
689
- sync_progress_element.innerHTML =
690
- '<strong>Progress:</strong> ' + remaining + ' item' +
691
- (remaining > 1 ? 's' : '') + ' remaining.';
692
- }
693
- if(remaining === 0){
694
- product_sync_complete(sync_progress_element);
695
- }
696
- } else {
697
- //Not processing, none remaining. Either long complete, or just completed
698
- if(window.fb_sync_start_time && res.request_time){
699
- var request_time = new Date(parseInt(res.request_time));
700
- if(window.fb_sync_start_time > request_time){
701
- //Old ping, do nothing.
702
- console.log("OLD PING");
703
- return;
704
- }
705
- }
706
-
707
- if(remaining === 0){
708
- product_sync_complete(sync_progress_element);
709
- }
710
- }
711
- }
712
- });
713
}
714
715
function parse_response_check_connection(res) {
716
- if (res) {
717
- console.log(res);
718
- var response = res.substring(res.indexOf("{")); //Trim leading extra chars (rnrnr)
719
- response = JSON.parse(response);
720
- if(!response.connected && !window.fb_connected){
721
- not_connected();
722
- return null;
723
- }
724
- return response;
725
- }
726
- return null;
727
}
728
729
function check_feed_upload_queue(check_num) {
730
- ajax('ajax_check_feed_upload_status', null, function(response) {
731
- var sync_progress_element = document.querySelector('#sync_progress');
732
- var res = parse_response_check_connection(response);
733
- clearInterval(window.fb_feed_pings);
734
- if (res) {
735
- var status = res.status;
736
- switch (status) {
737
- case 'complete':
738
- window.feed_upload = false;
739
- if (window.is_test) {
740
- display_test_result();
741
- } else {
742
- product_sync_complete(sync_progress_element);
743
- }
744
- break;
745
- case 'in progress':
746
- if (sync_progress_element) {
747
- sync_progress_element.innerHTML =
748
- 'Syncing... Keep this browser open <br/>' +
749
- 'Until sync is complete<br/>';
750
- }
751
- ping_feed_status_queue(check_num+1);
752
- break;
753
- default:
754
- sync_progress_element.innerHTML =
755
- '<strong>Something wrong when uploading, please try again.</strong>';
756
- window.feed_upload = false;
757
- if (window.is_test) {
758
- display_test_result();
759
- }
760
- }
761
- }
762
- });
763
}
764
765
function display_test_result() {
766
- ajax('ajax_display_test_result', null, function(response) {
767
- var sync_complete_element = document.querySelector('#sync_complete');
768
- var sync_progress_element = document.querySelector('#sync_progress');
769
- var res = parse_response_check_connection(response);
770
- if (res) {
771
- var status = res.pass;
772
- switch (status) {
773
- case 'true':
774
- sync_not_in_progress();
775
- if(sync_complete_element) {
776
- sync_complete_element.style.display = '';
777
- sync_complete_element.innerHTML =
778
- '<strong>Status: </strong>Test Pass.';
779
- }
780
- if(sync_progress_element) {
781
- sync_progress_element.innerHTML = '';
782
- }
783
- window.is_test = false;
784
- break;
785
- case 'in progress':
786
- if (sync_progress_element) {
787
- sync_progress_element.innerHTML =
788
- '<strong>Integration test in progress...</strong>';
789
- }
790
- ping_feed_status_queue();
791
- break;
792
- default:
793
- window.debug_info = res.debug_info + '<br/>' + res.stack_trace;
794
- if(sync_complete_element) {
795
- sync_complete_element.style.display = '';
796
- sync_complete_element.innerHTML =
797
- '<strong>Status: </strong>Test Fail.';
798
- }
799
- if (sync_progress_element) {
800
- sync_progress_element.innerHTML = '';
801
- }
802
- if(document.querySelector('#debug_info')) {
803
- document.querySelector('#debug_info').style.display = '';
804
- }
805
- window.is_test = false;
806
- }
807
- }
808
- });
809
}
810
811
function show_debug_info() {
812
- var stack_trace_element = document.querySelector('#stack_trace');
813
- if(stack_trace_element) {
814
- stack_trace_element.innerHTML = window.debug_info;
815
- }
816
- if(document.querySelector('#debug_info')) {
817
- document.querySelector('#debug_info').style.display = 'none';
818
- }
819
- window.debug_info = '';
820
}
821
822
function fbe_init_nux_messages() {
823
- var jQuery = window.jQuery;
824
- jQuery(function() {
825
- jQuery.each(jQuery('.nux-message'), function(_index, nux_msg) {
826
- var nux_msg_elem = jQuery(nux_msg);
827
- var targetid = nux_msg_elem.data('target');
828
- var target_elem = jQuery('#' + targetid);
829
- var t_pos = target_elem.position();
830
- var t_half_height = target_elem.height() / 2;
831
- var t_width = target_elem.outerWidth();
832
- nux_msg_elem.css({
833
- 'top': '' + Math.ceil(t_pos.top + t_half_height) + 'px',
834
- 'left': '' + Math.ceil(t_pos.left + t_width) + 'px',
835
- 'display': 'block'
836
- });
837
- jQuery('.nux-message-close-btn', nux_msg_elem).click(function() {
838
- jQuery(nux_msg).hide();
839
- });
840
- });
841
- });
842
}
843
844
function saveAutoSyncSchedule() {
845
- var isChecked = document.getElementsByClassName('autosyncCheck')[0].checked;
846
- var timebox = document.getElementsByClassName('autosyncTime')[0];
847
- var button = document.getElementsByClassName('autosyncSaveButton')[0];
848
- var saved = document.getElementsByClassName('autosyncSavedNotice')[0];
849
-
850
- if (!isChecked) {
851
- timebox.setAttribute('disabled', true);
852
- } else {
853
- timebox.removeAttribute('disabled');
854
- saved.style.transition = '';
855
- saved.style.opacity = 1;
856
- // Fade out the small 'Saved' after 3 seconds.
857
- setTimeout(function() {
858
- saved.style.opacity = 0;
859
- saved.style.transition = 'opacity 5s';}
860
- ,3000);
861
- }
862
-
863
- ajax('ajax_schedule_force_resync', {"enabled": isChecked ? 1 : 0, "time": timebox.value});
864
}
865
866
function onSetDisableSyncOnDevEnvironment() {
867
- var isChecked = document.getElementsByClassName('disableOnDevEnvironment')[0].checked;
868
- ajax(
869
- 'ajax_update_fb_option',
870
- {
871
- "option": "fb_disable_sync_on_dev_environment",
872
- "option_value": isChecked ? 1 : 0,
873
- "_ajax_nonce": wc_facebook_settings_jsx.nonce,
874
- },
875
- null,
876
- function onSetDisableSyncOnDevEnvironmentFailCallback(error) {
877
- document.getElementsByClassName(
878
- 'onSetDisableSyncOnDevEnvironment'
879
- )[0].checked = !isChecked;
880
- console.log('Failed to disable sync on dev environment');
881
- }
882
- );
883
}
884
885
function syncShortDescription() {
886
- var isChecked = document.getElementsByClassName('syncShortDescription')[0].checked;
887
- ajax(
888
- 'ajax_update_fb_option',
889
- {
890
- "option": "fb_sync_short_description",
891
- "option_value": isChecked ? 1 : 0,
892
- "_ajax_nonce": wc_facebook_settings_jsx.nonce,
893
- },
894
- null,
895
- function syncShortDescriptionFailCallback(error) {
896
- document.getElementsByClassName('syncShortDescription')[0].checked = ! isChecked;
897
- console.log('Failed to sync Short Description');
898
- }
899
- );
900
}
8
*/
9
10
var fb_sync_no_response_count = 0;
11
+ var fb_show_advanced_options = false;
12
13
function toggleAdvancedOptions() {
14
+ var opts = document.getElementById( "fbAdvancedOptions" );
15
+ if ( ! fb_show_advanced_options) {
16
+ opts.style.display = "block";
17
+ document.getElementById( 'fbAdvancedOptionsText' ).innerHTML = 'Hide Advanced Settings';
18
+ } else {
19
+ opts.style.display = "none";
20
+ document.getElementById( 'fbAdvancedOptionsText' ).innerHTML = 'Show Advanced Settings';
21
+ }
22
+ fb_show_advanced_options = ! fb_show_advanced_options;
23
}
24
25
function openPopup() {
26
+ var width = 1153;
27
+ var height = 808;
28
+ var topPos = screen.height / 2 - height / 2;
29
+ var leftPos = screen.width / 2 - width / 2;
30
+ window.originParam = window.location.protocol + '//' + window.location.host;
31
+ var popupUrl;
32
+ if (window.facebookAdsToolboxConfig.popupOrigin.includes( 'staticxx' )) {
33
+ window.facebookAdsToolboxConfig.popupOrigin = 'https://www.facebook.com/';
34
+ }
35
+ window.facebookAdsToolboxConfig.popupOrigin = prepend_protocol(
36
+ window.facebookAdsToolboxConfig.popupOrigin
37
+ );
38
+ popupUrl = window.facebookAdsToolboxConfig.popupOrigin;
39
+
40
+ var path = '/ads/dia';
41
+ var page = window.open( popupUrl + '/login.php?display=popup&next=' + encodeURIComponent( popupUrl + path + '?origin=' + window.originParam + ' &merchant_settings_id=' + window.facebookAdsToolboxConfig.diaSettingId ), 'DiaWizard', ['toolbar=no', 'location=no', 'directories=no', 'status=no', 'menubar=no', 'scrollbars=no', 'resizable=no', 'copyhistory=no', 'width=' + width, 'height=' + height, 'top=' + topPos, 'left=' + leftPos].join( ',' ) );
42
+
43
+ return function (type, params) {
44
+ page.postMessage(
45
+ {
46
+ type: type,
47
+ params: params
48
+ },
49
+ window.facebookAdsToolboxConfig.popupOrigin
50
+ );
51
+ };
52
}
53
54
function prepend_protocol(url) {
55
+ // Preprend https if the url begis with //www.
56
+ if (url.indexOf( '//www.' ) === 0) {
57
+ url = 'https:' + url;
58
+ }
59
+ return url;
60
}
61
62
function get_product_catalog_id_box() {
63
+ return document.querySelector( '#woocommerce_facebookcommerce_fb_product_catalog_id' ) || null;
64
}
65
function get_pixel_id_box() {
66
+ return document.querySelector( '#woocommerce_facebookcommerce_fb_pixel_id' ) || null;
67
}
68
function get_pixel_use_pii_id_box() {
69
+ return document.querySelector( '#woocommerce_facebookcommerce_fb_pixel_use_pii' ) || null;
70
}
71
function get_api_key_box() {
72
+ return document.querySelector( '#woocommerce_facebookcommerce_fb_api_key' ) || null;
73
}
74
function get_page_id_box() {
75
+ return document.querySelector( '#woocommerce_facebookcommerce_fb_page_id' ) || null;
76
}
77
function get_ems_id_box() {
78
+ return document.querySelector( '#woocommerce_facebookcommerce_fb_external_merchant_settings_id' ) || null;
79
}
80
81
/*
82
* Ajax helper function.
83
* Takes optional payload for POST and optional callback.
84
*/
85
+ function ajax(action, payload = null, callback = null, failcallback = null) {
86
+ var data = Object.assign(
87
+ {},
88
+ {
89
+ 'action': action,
90
+ },
91
+ payload
92
+ );
93
+
94
+ // Since Wordpress 2.8 ajaxurl is always defined in admin header and
95
+ // points to admin-ajax.php
96
+ jQuery.post(
97
+ ajaxurl,
98
+ data,
99
+ function(response) {
100
+ if (callback) {
101
+ callback( response );
102
+ }
103
+ }
104
+ ).fail(
105
+ function(errorResponse){
106
+ if (failcallback) {
107
+ failcallback( errorResponse );
108
+ }
109
+ }
110
+ );
111
+ }
112
+
113
+ var settings = {'facebook_for_woocommerce' : 1};
114
var pixel_settings = {'facebook_for_woocommerce' : 1};
115
116
function facebookConfig() {
117
+ window.sendToFacebook = openPopup();
118
+ window.diaConfig = { 'clientSetup': window.facebookAdsToolboxConfig };
119
}
120
121
function fb_flush(){
122
+ console.log( "Removing all FBIDs from all products!" );
123
+ return ajax(
124
+ 'ajax_reset_all_fb_products',
125
+ {"_ajax_nonce": wc_facebook_settings_jsx.nonce},
126
+ null,
127
+ function fb_flushFailCallback(error) {
128
+ console.log('Failed to reset all FB products');
129
+ }
130
+ );
131
}
132
133
function sync_confirm(verbose = null) {
134
+ var msg = '';
135
+ switch (verbose) {
136
+ case 'fb_force_resync':
137
+ msg = 'Your products will now be resynced with Facebook, ' +
138
+ 'this may take some time.';
139
+ break;
140
+ case 'fb_test_product_sync':
141
+ msg = 'Launch Test?';
142
+ break;
143
+ default:
144
+ msg = 'Facebook for WooCommerce automatically syncs your products on ' +
145
+ 'create/update. Are you sure you want to force product resync? ' +
146
+ 'This will query all published products and may take some time. ' +
147
+ 'You only need to do this if your products are out of sync ' +
148
+ 'or some of your products did not sync.';
149
+ }
150
+ if (confirm( msg )) {
151
+ sync_all_products(
152
+ window.facebookAdsToolboxConfig.feed.hasClientSideFeedUpload,
153
+ verbose == 'fb_test_product_sync'
154
+ );
155
+ window.fb_sync_start_time = new Date().getTime();
156
+ }
157
}
158
159
// Launch the confirm dialog immediately if the param is in the URL.
160
+ if (window.location.href.includes( "fb_force_resync" )) {
161
+ window.onload = function() { sync_confirm( "fb_force_resync" ); };
162
+ } else if (window.location.href.includes( "fb_test_product_sync" )) {
163
+ // Test products sync by feed.
164
+ window.is_test = true;
165
+ window.onload = function() { sync_confirm( "fb_test_product_sync" ); };
166
}
167
168
function sync_all_products($using_feed = false, $is_test = false) {
169
+ if (get_product_catalog_id_box() && ! get_product_catalog_id_box().value) {
170
+ return;
171
+ }
172
+ if (get_api_key_box() && ! get_api_key_box().value) {
173
+ return;
174
+ }
175
+ console.log( 'Syncing all products!' );
176
+ window.fb_connected = true;
177
+ sync_in_progress();
178
+ if ($using_feed) {
179
+ window.facebookAdsToolboxConfig.feed.hasClientSideFeedUpload = true;
180
+ window.feed_upload = true;
181
+ ping_feed_status_queue();
182
+ return $is_test ? ajax( 'ajax_test_sync_products_using_feed' )
183
+ : ajax(
184
+ 'ajax_sync_all_fb_products_using_feed',
185
+ {
186
+ "_ajax_nonce": wc_facebook_settings_jsx.nonce,
187
+ },
188
+ );
189
+ } else {
190
+ return ajax(
191
+ 'ajax_sync_all_fb_products',
192
+ {
193
+ "_ajax_nonce": wc_facebook_settings_jsx.nonce,
194
+ }
195
+ );
196
+ }
197
}
198
199
// Reset all state
200
function delete_all_settings(callback = null, failcallback = null) {
201
+ if (get_product_catalog_id_box()) {
202
+ get_product_catalog_id_box().value = '';
203
+ }
204
+ if (get_pixel_id_box()) {
205
+ get_pixel_id_box().value = '';
206
+ }
207
+ if (get_pixel_use_pii_id_box()) {
208
+ get_pixel_use_pii_id_box().checked = false;
209
+ }
210
+ if (get_api_key_box()) {
211
+ get_api_key_box().value = '';
212
+ }
213
+ if (get_page_id_box()) {
214
+ get_page_id_box().value = '';
215
+ }
216
+ if (get_ems_id_box()) {
217
+ get_ems_id_box().value = '';
218
+ }
219
+
220
+ window.facebookAdsToolboxConfig.pixel.pixelId = '';
221
+ window.facebookAdsToolboxConfig.diaSettingId = '';
222
+
223
+ reset_buttons();
224
+ window.fb_connected = false;
225
+
226
+ console.log( 'Deleting all settings and removing all FBIDs!' );
227
+ return ajax(
228
+ 'ajax_delete_fb_settings',
229
+ {
230
+ "_ajax_nonce": wc_facebook_settings_jsx.nonce,
231
+ },
232
+ callback,
233
+ failcallback
234
+ );
235
}
236
237
// save_settings and save_settings_and_sync should only be called once
241
// It's also called again if the pixel id is ever changed or pixel pii is
242
// enabled or disabled.
243
function save_settings(callback = null, failcallback = null, localsettings = null){
244
+ if ( ! localsettings) {
245
+ localsettings = settings;
246
+ }
247
+ localsettings["_ajax_nonce"] = wc_facebook_settings_jsx.nonce;
248
+ ajax(
249
+ 'ajax_save_fb_settings',
250
+ localsettings,
251
+ function(response){
252
+ if (callback) {
253
+ callback( response );
254
+ }
255
+ },
256
+ function(errorResponse){
257
+ if (failcallback) {
258
+ failcallback( errorResponse );
259
+ }
260
+ }
261
+ );
262
}
263
264
// save_settings wrapper for plugins as we do not need to:
265
+ // 1. sync products again after plugin is configured
266
+ // 2. check api_key, which is from facebook and is only necessary
267
+ // for following sync products
268
function save_settings_for_plugin(callback, failcallback) {
269
+ save_settings(
270
+ function(response){
271
+ if (response && response.includes( 'settings_saved' )) {
272
+ console.log( response );
273
+ callback( response );
274
+ } else {
275
+ console.log( 'Fail response on save_settings_and_sync' );
276
+ failcallback( response );
277
+ }
278
+ },
279
+ function(errorResponse){
280
+ console.log( 'Ajax error while saving settings:' + JSON.stringify( errorResponse ) );
281
+ failcallback( errorResponse );
282
+ }
283
+ );
284
}
285
286
// see comments in save_settings function above
287
function save_settings_and_sync(message) {
288
+ if ('api_key' in settings) {
289
+ save_settings(
290
+ function(response){
291
+ if (response && response.includes( 'settings_saved' )) {
292
+ console.log( response );
293
+ // Final acks
294
+ window.sendToFacebook( 'ack set pixel', message.params );
295
+ window.sendToFacebook( 'ack set page access token', message.params );
296
+ window.sendToFacebook( 'ack set merchant settings', message.params );
297
+ sync_all_products( true );
298
+ } else {
299
+ window.sendToFacebook( 'fail save_settings', response );
300
+ console.log( 'Fail response on save_settings_and_sync' );
301
+ }
302
+ },
303
+ function(errorResponse){
304
+ console.log( 'Ajax error while saving settings:' + JSON.stringify( errorResponse ) );
305
+ window.sendToFacebook( 'fail save_settings_ajax', JSON.stringify( errorResponse ) );
306
+ }
307
+ );
308
+ }
309
+ }
310
+
311
+ // Reset buttons to brand new setup state
312
function reset_buttons(){
313
+ if (document.querySelector( '#settings' )) {
314
+ document.querySelector( '#settings' ).style.display = 'none';
315
+ }
316
+ if (document.querySelector( '#cta_button' )) {
317
+ var cta_element = document.querySelector( '#cta_button' );
318
+ cta_element.innerHTML = 'Get Started';
319
+ cta_element.style['font-size'] = '13px';
320
+ cta_element.style.width = '80px';
321
+ cta_element.href = '#';
322
+ cta_element.onclick = function() { facebookConfig(); };
323
+ }
324
+ if (document.querySelector( '#learnmore_button' )) {
325
+ document.querySelector( '#learnmore_button' ).style.display = 'none';
326
+ }
327
+ if (document.querySelector( '#setup_h1' )) {
328
+ document.querySelector( '#setup_h1' ).innerHTML =
329
+ 'Grow your business on Facebook';
330
+ }
331
+ if (document.querySelector( '#setup_l1' )) {
332
+ document.querySelector( '#setup_l1' ).innerHTML =
333
+ 'Easily install a tracking pixel';
334
+ }
335
+ if (document.querySelector( '#setup_l2' )) {
336
+ document.querySelector( '#setup_l2' ).innerHTML =
337
+ 'Upload your products and create a shop';
338
+ }
339
+ if (document.querySelector( '#setup_l3' )) {
340
+ document.querySelector( '#setup_l3' ).innerHTML =
341
+ 'Create dynamic ads with your products and pixel';
342
+ }
343
+ }
344
+
345
+ // Remove reset/settings buttons during product sync
346
function sync_in_progress(){
347
+ if (document.querySelector( '#settings' )) {
348
+ document.querySelector( '#settings' ).style.display = '';
349
+ }
350
+ if (document.querySelector( '#connection_status' )) {
351
+ document.querySelector( '#connection_status' ).style.display = '';
352
+ }
353
+ if (document.querySelector( '#sync_complete' )) {
354
+ document.querySelector( '#sync_complete' ).style.display = 'none';
355
+ }
356
+ // Get rid of all the buttons
357
+ if (document.querySelector( '#setting_button' )) {
358
+ document.querySelector( '#setting_button' ).style['pointer-events'] = 'none';
359
+ }
360
+ if (document.querySelector( '#resync_products' )) {
361
+ document.querySelector( '#resync_products' ).style['pointer-events'] = 'none';
362
+ }
363
+ if (document.querySelector( '#test_product_sync' )) {
364
+ document.querySelector( '#test_product_sync' ).style.display = 'none';
365
+ }
366
+ // Set a product sync status
367
+ if (document.querySelector( '#sync_progress' )) {
368
+ document.querySelector( '#sync_progress' ).innerHTML =
369
+ 'Syncing... Keep this browser open <br/>' +
370
+ 'Until sync is complete<br/>' +
371
+ '<div class="loader"></div>';
372
+ }
373
}
374
375
function sync_not_in_progress(){
376
+ // Reset to pre-setup state.
377
+ if (document.querySelector( '#cta_button' )) {
378
+ var cta_element = document.querySelector( '#cta_button' );
379
+ cta_element.innerHTML = 'Create Ad';
380
+ cta_element.style['font-size'] = '12px';
381
+ cta_element.style.width = '60px';
382
+ if (window.facebookAdsToolboxConfig.diaSettingId) {
383
+ cta_element.onclick = function() {
384
+ window.open(
385
+ 'https://www.facebook.com/ads/dia/redirect/?settings_id=' +
386
+ window.facebookAdsToolboxConfig.diaSettingId + '&version=2' +
387
+ '&entry_point=admin_panel'
388
+ );
389
+ };
390
+ } else {
391
+ cta_element.style['pointer-events'] = 'none';
392
+ }
393
+ }
394
+ if (document.querySelector( '#learnmore_button' )) {
395
+ var learnmore_element = document.querySelector( '#learnmore_button' );
396
+ if (window.facebookAdsToolboxConfig.diaSettingId) {
397
+ learnmore_element.style.display = '';
398
+ }
399
+ }
400
+ if (document.querySelector( '#setup_h1' )) {
401
+ document.querySelector( '#setup_h1' ).innerHTML =
402
+ 'Reach the right people and sell more products';
403
+ }
404
+ if (document.querySelector( '#setup_l1' )) {
405
+ document.querySelector( '#setup_l1' ).innerHTML =
406
+ 'Create an ad in a few steps';
407
+ }
408
+ if (document.querySelector( '#setup_l2' )) {
409
+ document.querySelector( '#setup_l2' ).innerHTML =
410
+ 'Use built-in best practice for online sales';
411
+ }
412
+ if (document.querySelector( '#setup_l3' )) {
413
+ document.querySelector( '#setup_l3' ).innerHTML =
414
+ 'Get reporting on sales and revenue';
415
+ }
416
+ if (document.querySelector( '#settings' )) {
417
+ document.querySelector( '#settings' ).style.display = '';
418
+ }
419
+ // Enable buttons.
420
+ if (document.querySelector( '#setting_button' )) {
421
+ document.querySelector( '#setting_button' ).style['pointer-events'] = 'auto';
422
+ }
423
+ if (document.querySelector( '#resync_products' )) {
424
+ document.querySelector( '#resync_products' ).style ['pointer-events'] = 'auto';
425
+ }
426
+ // Remove sync progress.
427
+ if (document.querySelector( '#sync_progress' )) {
428
+ document.querySelector( '#sync_progress' ).innerHTML = '';
429
+ }
430
}
431
432
function not_connected(){
433
+ if (document.querySelector( '#connection_status' )) {
434
+ document.querySelector( '#connection_status' ).style.display = 'none';
435
+ }
436
+
437
+ if (document.querySelector( '#setting_button' )) {
438
+ document.querySelector( '#setting_button' ).style['pointer-events'] = 'auto';
439
+ }
440
+ if (document.querySelector( '#resync_products' )) {
441
+ document.querySelector( '#resync_products' ).style['pointer-events'] = 'none';
442
+ }
443
+ if (document.querySelector( '#sync_complete' )) {
444
+ document.querySelector( '#sync_complete' ).style.display = 'none';
445
+ }
446
+ if (document.querySelector( '#sync_progress' )) {
447
+ document.querySelector( '#sync_progress' ).innerHTML = '';
448
+ }
449
}
450
451
function addAnEventListener(obj,evt,func) {
452
+ if ('addEventListener' in obj) {
453
+ obj.addEventListener( evt,func, false );
454
+ } else if ('attachEvent' in obj) {// IE
455
+ obj.attachEvent( 'on' + evt,func );
456
+ }
457
}
458
459
function setMerchantSettings(message) {
460
+ if ( ! message.params.setting_id) {
461
+ console.error( 'Facebook Extension Error: got no setting_id', message.params );
462
+ window.sendToFacebook( 'fail set merchant settings', message.params );
463
+ return;
464
+ }
465
+ if (get_ems_id_box()) {
466
+ get_ems_id_box().value = message.params.setting_id;
467
+ }
468
469
+ settings.external_merchant_settings_id = message.params.setting_id;
470
471
+ // Immediately set in case button is clicked again
472
+ window.facebookAdsToolboxConfig.diaSettingId = message.params.setting_id;
473
+ // Ack merchant settings happens after settings are saved
474
}
475
476
function setCatalog(message) {
477
+ if ( ! message.params.catalog_id) {
478
+ console.error( 'Facebook Extension Error: got no catalog_id', message.params );
479
+ window.sendToFacebook( 'fail set catalog', message.params );
480
+ return;
481
+ }
482
+ if (get_api_key_box()) {
483
+ get_product_catalog_id_box().value = message.params.catalog_id;
484
+ }
485
486
+ settings.product_catalog_id = message.params.catalog_id;
487
488
+ window.sendToFacebook( 'ack set catalog', message.params );
489
}
490
491
492
function setPixel(message) {
493
+ if ( ! message.params.pixel_id) {
494
+ console.error( 'Facebook Ads Extension Error: got no pixel_id', message.params );
495
+ window.sendToFacebook( 'fail set pixel', message.params );
496
+ return;
497
+ }
498
+ if (get_pixel_id_box()) {
499
+ get_pixel_id_box().value = message.params.pixel_id;
500
+ }
501
+
502
+ settings.pixel_id = message.params.pixel_id;
503
+ pixel_settings.pixel_id = settings.pixel_id;
504
+ if (message.params.pixel_use_pii !== undefined) {
505
+ if (get_pixel_use_pii_id_box()) {
506
+ // !! will explicitly convert truthy/falsy values to a boolean
507
+ get_pixel_use_pii_id_box().checked = ! ! message.params.pixel_use_pii;
508
+ }
509
+ settings.pixel_use_pii = message.params.pixel_use_pii;
510
+ pixel_settings.pixel_use_pii = settings.pixel_use_pii;
511
+ }
512
+
513
+ // We need this to support changing the pixel id after setup.
514
+ save_settings(
515
+ function(response){
516
+ if (response && response.includes( 'settings_saved' )) {
517
+ window.sendToFacebook( 'ack set pixel', message.params );
518
+ } //may not get settings_saved if we try to save pixel before an API key
519
+ },
520
+ function(errorResponse){
521
+ console.log( errorResponse );
522
+ window.sendToFacebook( 'fail set pixel', errorResponse );
523
+ },
524
+ pixel_settings
525
+ );
526
}
527
528
function genFeed(message) {
529
+ // no-op
530
}
531
532
function setAccessTokenAndPageId(message) {
533
+ if ( ! message.params.page_token) {
534
+ console.error(
535
+ 'Facebook Ads Extension Error: got no page_token',
536
+ message.params
537
+ );
538
+ window.sendToFacebook( 'fail set page access token', message.params );
539
+ return;
540
+ }
541
+ /*
542
+ Set page_token here
543
+ */
544
+
545
+ if (get_api_key_box()) {
546
+ get_api_key_box().value = message.params.page_token;
547
+ }
548
+
549
+ if (get_page_id_box()) {
550
+ get_page_id_box().value = message.params.page_id;
551
+ }
552
+
553
+ settings.api_key = message.params.page_token;
554
+ settings.page_id = message.params.page_id;
555
+ // Ack token in "save_settings_and_sync" for final ack
556
+
557
+ window.facebookAdsToolboxConfig.tokenExpired = false;
558
+ if (document.querySelector( '#token_text' )) {
559
+ document.querySelector( '#token_text' ).innerHTML =
560
+ ` < strong > Your API key has been updated.<br / >
561
+ Please refresh the page.< / strong > `;
562
+ }
563
}
564
565
function setMsgerChatSetup(data) {
566
+ if (data.hasOwnProperty( 'is_messenger_chat_plugin_enabled' )) {
567
+ settings.is_messenger_chat_plugin_enabled =
568
+ data.is_messenger_chat_plugin_enabled;
569
+ }
570
+ if (data.hasOwnProperty( 'facebook_jssdk_version' )) {
571
+ settings.facebook_jssdk_version =
572
+ data.facebook_jssdk_version;
573
+ }
574
+ if (data.hasOwnProperty( 'page_id' )) {
575
+ settings.fb_page_id = data.page_id;
576
+ }
577
+
578
+ if (data.hasOwnProperty( 'customization' )) {
579
+ var customization = data.customization;
580
+
581
+ if (customization.hasOwnProperty( 'greetingTextCode' )) {
582
+ settings.msger_chat_customization_greeting_text_code =
583
+ customization.greetingTextCode;
584
+ }
585
+ if (customization.hasOwnProperty( 'locale' )) {
586
+ settings.msger_chat_customization_locale =
587
+ customization.locale;
588
+ }
589
+ if (customization.hasOwnProperty( 'themeColorCode' )) {
590
+ settings.msger_chat_customization_theme_color_code =
591
+ customization.themeColorCode;
592
+ }
593
+ }
594
}
595
596
function iFrameListener(event) {
597
+ // Fix for web.facebook.com
598
+ const origin = event.origin || event.originalEvent.origin;
599
+ if (origin != window.facebookAdsToolboxConfig.popupOrigin &&
600
+ urlFromSameDomain( origin, window.facebookAdsToolboxConfig.popupOrigin )) {
601
+ window.facebookAdsToolboxConfig.popupOrigin = origin;
602
+ }
603
+
604
+ switch (event.data.type) {
605
+ case 'reset':
606
+ delete_all_settings(
607
+ function(res){
608
+ if (res && event.data.params) {
609
+ if (res === 'Settings Deleted') {
610
+ window.sendToFacebook( 'ack reset', event.data.params );
611
+ } else {
612
+ console.log( res );
613
+ alert( res );
614
+ }
615
+ } else {
616
+ console.log( "Got no response from delete_all_settings" );
617
+ }
618
+ },
619
+ function(err){
620
+ console.error( err );
621
+ }
622
+ );
623
+ break;
624
+ case 'get dia settings':
625
+ window.sendToFacebook( 'dia settings', window.diaConfig );
626
+ break;
627
+ case 'set merchant settings':
628
+ setMerchantSettings( event.data );
629
+ break;
630
+ case 'set catalog':
631
+ setCatalog( event.data );
632
+ break;
633
+ case 'set pixel':
634
+ setPixel( event.data );
635
+ break;
636
+ case 'gen feed':
637
+ genFeed();
638
+ break;
639
+ case 'set page access token':
640
+ // Should be last message received
641
+ setAccessTokenAndPageId( event.data );
642
+ save_settings_and_sync( event.data );
643
+ break;
644
+ case 'set msger chat':
645
+ setMsgerChatSetup( event.data.params );
646
+ save_settings_for_plugin(
647
+ function(response) {
648
+ window.sendToFacebook( 'ack msger chat', event.data );
649
+ },
650
+ function(response) {
651
+ window.sendToFacebook( 'fail ack msger chat', event.data );
652
+ }
653
+ );
654
+ break;
655
+ }
656
+ }
657
+
658
+ addAnEventListener( window,'message',iFrameListener );
659
660
function urlFromSameDomain(url1, url2) {
661
+ if ( ! url1.startsWith( 'http' ) || ! url2.startsWith( 'http' )) {
662
+ return false;
663
+ }
664
+ var u1 = parseURL( url1 );
665
+ var u2 = parseURL( url2 );
666
+ var u1host = u1.host.replace( /^\w+\./, 'www.' );
667
+ var u2host = u2.host.replace( /^\w+\./, 'www.' );
668
+ return u1.protocol === u2.protocol && u1host === u2host;
669
}
670
671
function parseURL(url) {
672
+ var parser = document.createElement( 'a' );
673
+ parser.href = url;
674
+ return parser;
675
}
676
677
// Only do pings for supporting older (pre 1.8) setups.
678
window.fb_pings =
679
(window.facebookAdsToolboxConfig.feed.hasClientSideFeedUpload) ?
680
null :
681
+ setInterval(
682
+ function(){
683
+ console.log( "Pinging queue..." );
684
+ check_queues();
685
+ },
686
+ 10000
687
+ );
688
689
function ping_feed_status_queue(count = 0) {
690
+ window.fb_feed_pings = setInterval(
691
+ function() {
692
+ console.log( 'Pinging feed uploading queue...' );
693
+ check_feed_upload_queue( count );
694
+ },
695
+ 30000 * (1 << count)
696
+ );
697
+ }
698
+
699
+ function product_sync_complete(sync_progress_element) {
700
+ sync_not_in_progress();
701
+ if (document.querySelector( '#sync_complete' )) {
702
+ document.querySelector( '#sync_complete' ).style.display = '';
703
+ }
704
+ if (sync_progress_element) {
705
+ sync_progress_element.innerHTML = '';
706
+ }
707
+ clearInterval( window.fb_pings );
708
+ }
709
+
710
+ function check_queues() {
711
+ ajax(
712
+ 'ajax_fb_background_check_queue',
713
+ {
714
+ "request_time": new Date().getTime(),
715
+ "_ajax_nonce": wc_facebook_settings_jsx.nonce,
716
+ },
717
+ function( response ) {
718
+ if ( window.feed_upload ) {
719
+ clearInterval( window.fb_pings );
720
+ return;
721
+ }
722
+ var sync_progress_element = document.querySelector( '#sync_progress' );
723
+ var res = parse_response_check_connection( response );
724
+ if ( !res ) {
725
+ if ( fb_sync_no_response_count++ > 5 ) {
726
+ clearInterval( window.fb_pings );
727
+ }
728
+ return;
729
+ }
730
+ fb_sync_no_response_count = 0;
731
+
732
+ if ( res ) {
733
+ if ( !res.background ) {
734
+ console.log( "No background sync found, disabling pings" );
735
+ clearInterval( window.fb_pings );
736
+ }
737
+
738
+ var processing = !!res.processing; // explicit boolean conversion
739
+ var remaining = res.remaining;
740
+ if ( processing ) {
741
+ if ( sync_progress_element ) {
742
+ sync_progress_element.innerHTML =
743
+ '<strong>Progress:</strong> ' + remaining + ' item' +
744
+ ( remaining > 1 ? 's' : '' ) + ' remaining.';
745
+ }
746
+ if ( remaining === 0 ) {
747
+ product_sync_complete( sync_progress_element );
748
+ }
749
+ } else {
750
+ // Not processing, none remaining. Either long complete, or just completed
751
+ if ( window.fb_sync_start_time && res.request_time ) {
752
+ var request_time = new Date( parseInt( res.request_time ) );
753
+ if ( window.fb_sync_start_time > request_time ) {
754
+ // Old ping, do nothing.
755
+ console.log( "OLD PING" );
756
+ return;
757
+ }
758
+ }
759
+
760
+ if ( remaining === 0 ) {
761
+ product_sync_complete( sync_progress_element );
762
+ }
763
+ }
764
+ }
765
+ }
766
+ );
767
}
768
769
function parse_response_check_connection(res) {
770
+ if (res) {
771
+ console.log( res );
772
+ var response = res.substring( res.indexOf( "{" ) ); // Trim leading extra chars (rnrnr)
773
+ response = JSON.parse( response );
774
+ if ( ! response.connected && ! window.fb_connected) {
775
+ not_connected();
776
+ return null;
777
+ }
778
+ return response;
779
+ }
780
+ return null;
781
}
782
783
function check_feed_upload_queue(check_num) {
784
+ ajax(
785
+ 'ajax_check_feed_upload_status',
786
+ {
787
+ "_ajax_nonce": wc_facebook_settings_jsx.nonce,
788
+ },
789
+ function(response) {
790
+ var sync_progress_element = document.querySelector( '#sync_progress' );
791
+ var res = parse_response_check_connection( response );
792
+ clearInterval( window.fb_feed_pings );
793
+ if (res) {
794
+ var status = res.status;
795
+ switch (status) {
796
+ case 'complete':
797
+ window.feed_upload = false;
798
+ if (window.is_test) {
799
+ display_test_result();
800
+ } else {
801
+ product_sync_complete( sync_progress_element );
802
+ }
803
+ break;
804
+ case 'in progress':
805
+ if (sync_progress_element) {
806
+ sync_progress_element.innerHTML =
807
+ 'Syncing... Keep this browser open <br/>' +
808
+ 'Until sync is complete<br/>';
809
+ }
810
+ ping_feed_status_queue( check_num + 1 );
811
+ break;
812
+ default:
813
+ sync_progress_element.innerHTML =
814
+ '<strong>Something wrong when uploading, please try again.</strong>';
815
+ window.feed_upload = false;
816
+ if (window.is_test) {
817
+ display_test_result();
818
+ }
819
+ }
820
+ }
821
+ }
822
+ );
823
}
824
825
function display_test_result() {
826
+ ajax(
827
+ 'ajax_display_test_result',
828
+ {
829
+ "_ajax_nonce": wc_facebook_settings_jsx.nonce
830
+ },
831
+ function(response) {
832
+ var sync_complete_element = document.querySelector( '#sync_complete' );
833
+ var sync_progress_element = document.querySelector( '#sync_progress' );
834
+ var res = parse_response_check_connection( response );
835
+ if (res) {
836
+ var status = res.pass;
837
+ switch (status) {
838
+ case 'true':
839
+ sync_not_in_progress();
840
+ if (sync_complete_element) {
841
+ sync_complete_element.style.display = '';
842
+ sync_complete_element.innerHTML =
843
+ '<strong>Status: </strong>Test Pass.';
844
+ }
845
+ if (sync_progress_element) {
846
+ sync_progress_element.innerHTML = '';
847
+ }
848
+ window.is_test = false;
849
+ break;
850
+ case 'in progress':
851
+ if (sync_progress_element) {
852
+ sync_progress_element.innerHTML =
853
+ '<strong>Integration test in progress...</strong>';
854
+ }
855
+ ping_feed_status_queue();
856
+ break;
857
+ default:
858
+ window.debug_info = res.debug_info + '<br/>' + res.stack_trace;
859
+ if (sync_complete_element) {
860
+ sync_complete_element.style.display = '';
861
+ sync_complete_element.innerHTML =
862
+ '<strong>Status: </strong>Test Fail.';
863
+ }
864
+ if (sync_progress_element) {
865
+ sync_progress_element.innerHTML = '';
866
+ }
867
+ if (document.querySelector( '#debug_info' )) {
868
+ document.querySelector( '#debug_info' ).style.display = '';
869
+ }
870
+ window.is_test = false;
871
+ }
872
+ }
873
+ }
874
+ );
875
}
876
877
function show_debug_info() {
878
+ var stack_trace_element = document.querySelector( '#stack_trace' );
879
+ if (stack_trace_element) {
880
+ stack_trace_element.innerHTML = window.debug_info;
881
+ }
882
+ if (document.querySelector( '#debug_info' )) {
883
+ document.querySelector( '#debug_info' ).style.display = 'none';
884
+ }
885
+ window.debug_info = '';
886
}
887
888
function fbe_init_nux_messages() {
889
+ var jQuery = window.jQuery;
890
+ jQuery(
891
+ function() {
892
+ jQuery.each(
893
+ jQuery( '.nux-message' ),
894
+ function(_index, nux_msg) {
895
+ var nux_msg_elem = jQuery( nux_msg );
896
+ var targetid = nux_msg_elem.data( 'target' );
897
+ var target_elem = jQuery( '#' + targetid );
898
+ var t_pos = target_elem.position();
899
+ var t_half_height = target_elem.height() / 2;
900
+ var t_width = target_elem.outerWidth();
901
+ nux_msg_elem.css(
902
+ {
903
+ 'top': '' + Math.ceil( t_pos.top + t_half_height ) + 'px',
904
+ 'left': '' + Math.ceil( t_pos.left + t_width ) + 'px',
905
+ 'display': 'block'
906
+ }
907
+ );
908
+ jQuery( '.nux-message-close-btn', nux_msg_elem ).click(
909
+ function() {
910
+ jQuery( nux_msg ).hide();
911
+ }
912
+ );
913
+ }
914
+ );
915
+ }
916
+ );
917
}
918
919
function saveAutoSyncSchedule() {
920
+ var isChecked = document.getElementsByClassName( 'autosyncCheck' )[0].checked;
921
+ var timebox = document.getElementsByClassName( 'autosyncTime' )[0];
922
+ var button = document.getElementsByClassName( 'autosyncSaveButton' )[0];
923
+ var saved = document.getElementsByClassName( 'autosyncSavedNotice' )[0];
924
+
925
+ if ( ! isChecked) {
926
+ timebox.setAttribute( 'disabled', true );
927
+ } else {
928
+ timebox.removeAttribute( 'disabled' );
929
+ saved.style.transition = '';
930
+ saved.style.opacity = 1;
931
+ // Fade out the small 'Saved' after 3 seconds.
932
+ setTimeout(
933
+ function() {
934
+ saved.style.opacity = 0;
935
+ saved.style.transition = 'opacity 5s';}
936
+ ,
937
+ 3000
938
+ );
939
+ }
940
+
941
+ ajax( 'ajax_schedule_force_resync',
942
+ {
943
+ "enabled": isChecked ? 1 : 0,
944
+ "time" : timebox.value,
945
+ "_ajax_nonce": wc_facebook_settings_jsx.nonce,
946
+ }
947
+ );
948
}
949
950
function onSetDisableSyncOnDevEnvironment() {
951
+ var isChecked = document.getElementsByClassName( 'disableOnDevEnvironment' )[0].checked;
952
+ ajax(
953
+ 'ajax_update_fb_option',
954
+ {
955
+ "option": "fb_disable_sync_on_dev_environment",
956
+ "option_value": isChecked ? 1 : 0,
957
+ "_ajax_nonce": wc_facebook_settings_jsx.nonce,
958
+ },
959
+ null,
960
+ function onSetDisableSyncOnDevEnvironmentFailCallback(error) {
961
+ document.getElementsByClassName(
962
+ 'onSetDisableSyncOnDevEnvironment'
963
+ )[0].checked = ! isChecked;
964
+ console.log( 'Failed to disable sync on dev environment' );
965
+ }
966
+ );
967
}
968
969
function syncShortDescription() {
970
+ var isChecked = document.getElementsByClassName( 'syncShortDescription' )[0].checked;
971
+ ajax(
972
+ 'ajax_update_fb_option',
973
+ {
974
+ "option": "fb_sync_short_description",
975
+ "option_value": isChecked ? 1 : 0,
976
+ "_ajax_nonce": wc_facebook_settings_jsx.nonce,
977
+ },
978
+ null,
979
+ function syncShortDescriptionFailCallback(error) {
980
+ document.getElementsByClassName( 'syncShortDescription' )[0].checked = ! isChecked;
981
+ console.log( 'Failed to sync Short Description' );
982
+ }
983
+ );
984
}
changelog.txt CHANGED
@@ -1,4 +1,9 @@
1
*** Facebook for WooCommerce Changelog ***
2
2019-06-20 - Version 1.9.14
3
* Revisit CSRF security issue
4
* Remove rest controller which is not used
1
*** Facebook for WooCommerce Changelog ***
2
+ 2019-06-27 - Version 1.9.15
3
+ * CSRF handling for Ajax calls like ajax_woo_infobanner_post_click, ajax_woo_infobanner_post_xout, ajax_fb_toggle_visibility
4
+ * use phpcs to adhere to WP coding standards
5
+ * Minor UI changes on the iFrame
6
+
7
2019-06-20 - Version 1.9.14
8
* Revisit CSRF security issue
9
* Remove rest controller which is not used
facebook-commerce-events-tracker.php CHANGED
@@ -8,379 +8,426 @@
8
* @package FacebookCommerce
9
*/
10
11
- if (!class_exists('WC_Facebookcommerce_EventsTracker')) :
12
-
13
- if (!class_exists('WC_Facebookcommerce_Utils')) {
14
- include_once 'includes/fbutils.php';
15
- }
16
-
17
- if (!class_exists('WC_Facebookcommerce_Pixel')) {
18
- include_once 'facebook-commerce-pixel-event.php';
19
- }
20
-
21
- class WC_Facebookcommerce_EventsTracker {
22
- private $pixel;
23
- private static $isEnabled = true;
24
- const FB_PRIORITY_HIGH = 2;
25
- const FB_PRIORITY_LOW = 11;
26
-
27
- public function __construct($user_info) {
28
- $this->pixel = new WC_Facebookcommerce_Pixel($user_info);
29
-
30
- add_action('wp_head', array($this, 'apply_filters'));
31
-
32
- // Pixel Tracking Hooks
33
- add_action('wp_head',
34
- array($this, 'inject_base_pixel'));
35
- add_action('wp_footer',
36
- array($this, 'inject_base_pixel_noscript'));
37
- add_action('woocommerce_after_single_product',
38
- array($this, 'inject_view_content_event'), self::FB_PRIORITY_HIGH);
39
- add_action('woocommerce_after_shop_loop',
40
- array($this, 'inject_view_category_event'));
41
- add_action('pre_get_posts',
42
- array($this, 'inject_search_event'));
43
- add_action('woocommerce_after_cart',
44
- array($this, 'inject_add_to_cart_redirect_event'));
45
- add_action('woocommerce_add_to_cart',
46
- array($this, 'inject_add_to_cart_event'), self::FB_PRIORITY_HIGH);
47
- add_action('wc_ajax_fb_inject_add_to_cart_event',
48
- array($this, 'inject_ajax_add_to_cart_event' ), self::FB_PRIORITY_HIGH);
49
- add_action('woocommerce_after_checkout_form',
50
- array($this, 'inject_initiate_checkout_event'));
51
- add_action('woocommerce_thankyou',
52
- array($this, 'inject_gateway_purchase_event'), self::FB_PRIORITY_HIGH);
53
- add_action('woocommerce_payment_complete',
54
- array($this, 'inject_purchase_event'), self::FB_PRIORITY_HIGH);
55
- add_action('wpcf7_contact_form',
56
- array($this, 'inject_lead_event_hook'), self::FB_PRIORITY_LOW);
57
-
58
- }
59
-
60
- public function apply_filters() {
61
- self::$isEnabled = apply_filters(
62
- "facebook_for_woocommerce_integration_pixel_enabled",
63
- self::$isEnabled);
64
- }
65
-
66
- /**
67
- * Base pixel code to be injected on page head. Because of this, it's better
68
- * to echo the return value than using
69
- * WC_Facebookcommerce_Utils::wc_enqueue_js() in this case
70
- */
71
- public function inject_base_pixel() {
72
- if (self::$isEnabled) {
73
- echo $this->pixel->pixel_base_code();
74
- }
75
- }
76
-
77
- /**
78
- * Base pixel noscript to be injected on page body. This is to avoid W3
79
- * validation error.
80
- */
81
- public function inject_base_pixel_noscript() {
82
- if (self::$isEnabled) {
83
- echo $this->pixel->pixel_base_code_noscript();
84
- }
85
- }
86
-
87
- /**
88
- * Triggers ViewCategory for product category listings
89
- */
90
- public function inject_view_category_event() {
91
- global $wp_query;
92
- if (!self::$isEnabled) {
93
- return;
94
- }
95
-
96
- $products = array_values(array_map(function($item) {
97
- return wc_get_product($item->ID);
98
- },
99
- $wp_query->posts));
100
-
101
- // if any product is a variant, fire the pixel with
102
- // content_type: product_group
103
- $content_type = 'product';
104
- $product_ids = array();
105
- foreach ($products as $product) {
106
- if (!$product) {
107
- continue;
108
- }
109
- $product_ids = array_merge(
110
- $product_ids,
111
- WC_Facebookcommerce_Utils::get_fb_content_ids($product));
112
- if (WC_Facebookcommerce_Utils::is_variable_type($product->get_type())) {
113
- $content_type = 'product_group';
114
- }
115
- }
116
-
117
- $categories =
118
- WC_Facebookcommerce_Utils::get_product_categories(get_the_ID());
119
-
120
- $this->pixel->inject_event(
121
- 'ViewCategory',
122
- array(
123
- 'content_name' => $categories['name'],
124
- 'content_category' => $categories['categories'],
125
- 'content_ids' => json_encode(array_slice($product_ids, 0, 10)),
126
- 'content_type' => $content_type
127
- ),
128
- 'trackCustom');
129
- }
130
-
131
- /**
132
- * Triggers Search for result pages (deduped)
133
- */
134
- public function inject_search_event() {
135
- if (!self::$isEnabled) {
136
- return;
137
- }
138
-
139
- if (!is_admin() && is_search() && get_search_query() !== '') {
140
- if ($this->pixel->check_last_event('Search')) {
141
- return;
142
- }
143
-
144
- if (WC_Facebookcommerce_Utils::isWoocommerceIntegration()) {
145
- $this->actually_inject_search_event();
146
- } else {
147
- add_action('wp_head', array($this, 'actually_inject_search_event'), 11);
148
- }
149
- }
150
- }
151
-
152
- /**
153
- * Triggers Search for result pages
154
- */
155
- public function actually_inject_search_event() {
156
- if (!self::$isEnabled) {
157
- return;
158
- }
159
-
160
- $this->pixel->inject_event(
161
- 'Search',
162
- array(
163
- 'search_string' => get_search_query()
164
- ));
165
- }
166
-
167
- /**
168
- * Helper function to iterate through a cart and gather all content ids
169
- */
170
- private function get_content_ids_from_cart($cart) {
171
- $product_ids = array();
172
- foreach ($cart as $item) {
173
- $product_ids = array_merge(
174
- $product_ids,
175
- WC_Facebookcommerce_Utils::get_fb_content_ids($item['data']));
176
- }
177
- return $product_ids;
178
- }
179
-
180
- /**
181
- * Triggers ViewContent product pages
182
- */
183
- public function inject_view_content_event() {
184
- if (!self::$isEnabled) {
185
- return;
186
- }
187
- global $post;
188
- $product = wc_get_product($post->ID);
189
- $content_type = 'product_group';
190
- if (!$product) {
191
- return;
192
- }
193
-
194
- // if product is a variant, fire the pixel with content_type: product_group
195
- if (WC_Facebookcommerce_Utils::is_variation_type($product->get_type())) {
196
- $content_type = 'product';
197
- }
198
-
199
- $content_ids = WC_Facebookcommerce_Utils::get_fb_content_ids($product);
200
- $this->pixel->inject_event(
201
- 'ViewContent',
202
- array(
203
- 'content_name' => $product->get_title(),
204
- 'content_ids' => json_encode($content_ids),
205
- 'content_type' => $content_type,
206
- 'value' => $product->get_price(),
207
- 'currency' => get_woocommerce_currency()
208
- ));
209
- }
210
-
211
- /**
212
- * Triggers AddToCart for cart page and add_to_cart button clicks
213
- */
214
- public function inject_add_to_cart_event() {
215
- if (!self::$isEnabled) {
216
- return;
217
- }
218
-
219
- $product_ids = $this->get_content_ids_from_cart(WC()->cart->get_cart());
220
-
221
- $this->pixel->inject_event(
222
- 'AddToCart',
223
- array(
224
- 'content_ids' => json_encode($product_ids),
225
- 'content_type' => 'product',
226
- 'value' => WC()->cart->total,
227
- 'currency' => get_woocommerce_currency()
228
- ));
229
- }
230
-
231
- /**
232
- * Triggered by add_to_cart jquery trigger
233
- */
234
- public function inject_ajax_add_to_cart_event() {
235
- if (!self::$isEnabled) {
236
- return;
237
- }
238
-
239
- ob_start();
240
-
241
- echo '<script>';
242
-
243
- $product_ids = $this->get_content_ids_from_cart(WC()->cart->get_cart());
244
-
245
- echo $this->pixel->build_event(
246
- 'AddToCart',
247
- array(
248
- 'content_ids' => json_encode($product_ids),
249
- 'content_type' => 'product',
250
- 'value' => WC()->cart->total,
251
- 'currency' => get_woocommerce_currency()
252
- ));
253
- echo '</script>';
254
-
255
- $pixel = ob_get_clean();
256
-
257
- wp_send_json($pixel);
258
- }
259
-
260
- /**
261
- * Trigger AddToCart for cart page and woocommerce_after_cart hook.
262
- * When set 'redirect to cart', ajax call for button click and
263
- * woocommerce_add_to_cart will be skipped.
264
- */
265
- public function inject_add_to_cart_redirect_event() {
266
- if (!self::$isEnabled) {
267
- return;
268
- }
269
- $redirect_checked = get_option('woocommerce_cart_redirect_after_add', 'no');
270
- if ($redirect_checked == 'yes') {
271
- $this->inject_add_to_cart_event();
272
- }
273
- }
274
-
275
- /**
276
- * Triggers InitiateCheckout for checkout page
277
- */
278
- public function inject_initiate_checkout_event() {
279
- if (!self::$isEnabled ||
280
- $this->pixel->check_last_event('InitiateCheckout')) {
281
- return;
282
- }
283
-
284
- $product_ids = $this->get_content_ids_from_cart(WC()->cart->get_cart());
285
-
286
- $this->pixel->inject_event(
287
- 'InitiateCheckout',
288
- array(
289
- 'num_items' => WC()->cart->get_cart_contents_count(),
290
- 'content_ids' => json_encode($product_ids),
291
- 'content_type' => 'product',
292
- 'value' => WC()->cart->total,
293
- 'currency' => get_woocommerce_currency()
294
- ));
295
- }
296
-
297
- /**
298
- * Triggers Purchase for payment transaction complete and for the thank you
299
- * page in cases of delayed payment.
300
- */
301
- public function inject_purchase_event($order_id) {
302
- if (!self::$isEnabled ||
303
- $this->pixel->check_last_event('Purchase')) {
304
- return;
305
- }
306
-
307
- $this->inject_subscribe_event($order_id);
308
-
309
- $order = new WC_Order($order_id);
310
- $content_type = 'product';
311
- $product_ids = array();
312
- foreach ($order->get_items() as $item) {
313
- $product = wc_get_product($item['product_id']);
314
- $product_ids = array_merge(
315
- $product_ids,
316
- WC_Facebookcommerce_Utils::get_fb_content_ids($product));
317
- if (WC_Facebookcommerce_Utils::is_variable_type($product->get_type())) {
318
- $content_type = 'product_group';
319
- }
320
- }
321
-
322
- $this->pixel->inject_event(
323
- 'Purchase',
324
- array(
325
- 'content_ids' => json_encode($product_ids),
326
- 'content_type' => $content_type,
327
- 'value' => $order->get_total(),
328
- 'currency' => get_woocommerce_currency()
329
- ));
330
- }
331
-
332
- /**
333
- * Triggers Subscribe for payment transaction complete of purchase with
334
- * subscription.
335
- */
336
- public function inject_subscribe_event($order_id) {
337
- if (!function_exists("wcs_get_subscriptions_for_order")) {
338
- return;
339
- }
340
-
341
- $subscription_ids = wcs_get_subscriptions_for_order($order_id);
342
- foreach ($subscription_ids as $subscription_id) {
343
- $subscription = new WC_Subscription($subscription_id);
344
- $this->pixel->inject_event(
345
- 'Subscribe',
346
- array(
347
- 'sign_up_fee' => $subscription->get_sign_up_fee(),
348
- 'value' => $subscription->get_total(),
349
- 'currency' => get_woocommerce_currency()
350
- ));
351
- }
352
- }
353
-
354
- /**
355
- * Triggers Purchase for thank you page for COD, BACS CHEQUE payment
356
- * which won't invoke woocommerce_payment_complete.
357
- */
358
- public function inject_gateway_purchase_event($order_id) {
359
- if (!self::$isEnabled ||
360
- $this->pixel->check_last_event('Purchase')) {
361
- return;
362
- }
363
-
364
- $order = new WC_Order($order_id);
365
- $payment = $order->get_payment_method();
366
- $this->inject_purchase_event($order_id);
367
- $this->inject_subscribe_event($order_id);
368
- }
369
-
370
- /** Contact Form 7 Support **/
371
- public function inject_lead_event_hook() {
372
- add_action('wp_footer', array($this, 'inject_lead_event'), 11);
373
- }
374
-
375
- public function inject_lead_event() {
376
- if (!is_admin()) {
377
- $this->pixel->inject_conditional_event(
378
- 'Lead',
379
- array(),
380
- 'wpcf7submit',
381
- '{ em: event.detail.inputs.filter(ele => ele.name.includes("email"))[0].value }');
382
- }
383
- }
384
- }
385
386
endif;
8
* @package FacebookCommerce
9
*/
10
11
+ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
12
+
13
+ if ( ! class_exists( 'WC_Facebookcommerce_Utils' ) ) {
14
+ include_once 'includes/fbutils.php';
15
+ }
16
+
17
+ if ( ! class_exists( 'WC_Facebookcommerce_Pixel' ) ) {
18
+ include_once 'facebook-commerce-pixel-event.php';
19
+ }
20
+
21
+ class WC_Facebookcommerce_EventsTracker {
22
+ private $pixel;
23
+ private static $isEnabled = true;
24
+ const FB_PRIORITY_HIGH = 2;
25
+ const FB_PRIORITY_LOW = 11;
26
+
27
+ public function __construct( $user_info ) {
28
+ $this->pixel = new WC_Facebookcommerce_Pixel( $user_info );
29
+
30
+ add_action( 'wp_head', array( $this, 'apply_filters' ) );
31
+
32
+ // Pixel Tracking Hooks
33
+ add_action(
34
+ 'wp_head',
35
+ array( $this, 'inject_base_pixel' )
36
+ );
37
+ add_action(
38
+ 'wp_footer',
39
+ array( $this, 'inject_base_pixel_noscript' )
40
+ );
41
+ add_action(
42
+ 'woocommerce_after_single_product',
43
+ array( $this, 'inject_view_content_event' ),
44
+ self::FB_PRIORITY_HIGH
45
+ );
46
+ add_action(
47
+ 'woocommerce_after_shop_loop',
48
+ array( $this, 'inject_view_category_event' )
49
+ );
50
+ add_action(
51
+ 'pre_get_posts',
52
+ array( $this, 'inject_search_event' )
53
+ );
54
+ add_action(
55
+ 'woocommerce_after_cart',
56
+ array( $this, 'inject_add_to_cart_redirect_event' )
57
+ );
58
+ add_action(
59
+ 'woocommerce_add_to_cart',
60
+ array( $this, 'inject_add_to_cart_event' ),
61
+ self::FB_PRIORITY_HIGH
62
+ );
63
+ add_action(
64
+ 'wc_ajax_fb_inject_add_to_cart_event',
65
+ array( $this, 'inject_ajax_add_to_cart_event' ),
66
+ self::FB_PRIORITY_HIGH
67
+ );
68
+ add_action(
69
+ 'woocommerce_after_checkout_form',
70
+ array( $this, 'inject_initiate_checkout_event' )
71
+ );
72
+ add_action(
73
+ 'woocommerce_thankyou',
74
+ array( $this, 'inject_gateway_purchase_event' ),
75
+ self::FB_PRIORITY_HIGH
76
+ );
77
+ add_action(
78
+ 'woocommerce_payment_complete',
79
+ array( $this, 'inject_purchase_event' ),
80
+ self::FB_PRIORITY_HIGH
81
+ );
82
+ add_action(
83
+ 'wpcf7_contact_form',
84
+ array( $this, 'inject_lead_event_hook' ),
85
+ self::FB_PRIORITY_LOW
86
+ );
87
+
88
+ }
89
+
90
+ public function apply_filters() {
91
+ self::$isEnabled = apply_filters(
92
+ 'facebook_for_woocommerce_integration_pixel_enabled',
93
+ self::$isEnabled
94
+ );
95
+ }
96
+
97
+ /**
98
+ * Base pixel code to be injected on page head. Because of this, it's better
99
+ * to echo the return value than using
100
+ * WC_Facebookcommerce_Utils::wc_enqueue_js() in this case
101
+ */
102
+ public function inject_base_pixel() {
103
+ if ( self::$isEnabled ) {
104
+ echo $this->pixel->pixel_base_code();
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Base pixel noscript to be injected on page body. This is to avoid W3
110
+ * validation error.
111
+ */
112
+ public function inject_base_pixel_noscript() {
113
+ if ( self::$isEnabled ) {
114
+ echo $this->pixel->pixel_base_code_noscript();
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Triggers ViewCategory for product category listings
120
+ */
121
+ public function inject_view_category_event() {
122
+ global $wp_query;
123
+ if ( ! self::$isEnabled ) {
124
+ return;
125
+ }
126
+
127
+ $products = array_values(
128
+ array_map(
129
+ function( $item ) {
130
+ return wc_get_product( $item->ID );
131
+ },
132
+ $wp_query->posts
133
+ )
134
+ );
135
+
136
+ // if any product is a variant, fire the pixel with
137
+ // content_type: product_group
138
+ $content_type = 'product';
139
+ $product_ids = array();
140
+ foreach ( $products as $product ) {
141
+ if ( ! $product ) {
142
+ continue;
143
+ }
144
+ $product_ids = array_merge(
145
+ $product_ids,
146
+ WC_Facebookcommerce_Utils::get_fb_content_ids( $product )
147
+ );
148
+ if ( WC_Facebookcommerce_Utils::is_variable_type( $product->get_type() ) ) {
149
+ $content_type = 'product_group';
150
+ }
151
+ }
152
+
153
+ $categories =
154
+ WC_Facebookcommerce_Utils::get_product_categories( get_the_ID() );
155
+
156
+ $this->pixel->inject_event(
157
+ 'ViewCategory',
158
+ array(
159
+ 'content_name' => $categories['name'],
160
+ 'content_category' => $categories['categories'],
161
+ 'content_ids' => json_encode( array_slice( $product_ids, 0, 10 ) ),
162
+ 'content_type' => $content_type,
163
+ ),
164
+ 'trackCustom'
165
+ );
166
+ }
167
+
168
+ /**
169
+ * Triggers Search for result pages (deduped)
170
+ */
171
+ public function inject_search_event() {
172
+ if ( ! self::$isEnabled ) {
173
+ return;
174
+ }
175
+
176
+ if ( ! is_admin() && is_search() && get_search_query() !== '' ) {
177
+ if ( $this->pixel->check_last_event( 'Search' ) ) {
178
+ return;
179
+ }
180
+
181
+ if ( WC_Facebookcommerce_Utils::isWoocommerceIntegration() ) {
182
+ $this->actually_inject_search_event();
183
+ } else {
184
+ add_action( 'wp_head', array( $this, 'actually_inject_search_event' ), 11 );
185
+ }
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Triggers Search for result pages
191
+ */
192
+ public function actually_inject_search_event() {
193
+ if ( ! self::$isEnabled ) {
194
+ return;
195
+ }
196
+
197
+ $this->pixel->inject_event(
198
+ 'Search',
199
+ array(
200
+ 'search_string' => get_search_query(),
201
+ )
202
+ );
203
+ }
204
+
205
+ /**
206
+ * Helper function to iterate through a cart and gather all content ids
207
+ */
208
+ private function get_content_ids_from_cart( $cart ) {
209
+ $product_ids = array();
210
+ foreach ( $cart as $item ) {
211
+ $product_ids = array_merge(
212
+ $product_ids,
213
+ WC_Facebookcommerce_Utils::get_fb_content_ids( $item['data'] )
214
+ );
215
+ }
216
+ return $product_ids;
217
+ }
218
+
219
+ /**
220
+ * Triggers ViewContent product pages
221
+ */
222
+ public function inject_view_content_event() {
223
+ if ( ! self::$isEnabled ) {
224
+ return;
225
+ }
226
+ global $post;
227
+ $product = wc_get_product( $post->ID );
228
+ $content_type = 'product_group';
229
+ if ( ! $product ) {
230
+ return;
231
+ }
232
+
233
+ // if product is a variant, fire the pixel with content_type: product_group
234
+ if ( WC_Facebookcommerce_Utils::is_variation_type( $product->get_type() ) ) {
235
+ $content_type = 'product';
236
+ }
237
+
238
+ $content_ids = WC_Facebookcommerce_Utils::get_fb_content_ids( $product );
239
+ $this->pixel->inject_event(
240
+ 'ViewContent',
241
+ array(
242
+ 'content_name' => $product->get_title(),
243