Facebook for WooCommerce - Version 1.10.2

Version Description

Download this release

Release Info

Developer SkyVerge
Plugin Icon Facebook for WooCommerce
Version 1.10.2
Comparing to
See all releases

Code changes from version 1.10.1 to 1.10.2

assets/css/facebook.css CHANGED
@@ -274,9 +274,7 @@
274
}
275
276
#sync_progress {
277
- font-size: 0.9em;
278
font-weight: normal;
279
- margin-left: 10px;
280
}
281
282
#sync_progress .spinner {
274
}
275
276
#sync_progress {
277
font-weight: normal;
278
}
279
280
#sync_progress .spinner {
assets/js/admin/facebook-for-woocommerce-settings-sync.js CHANGED
@@ -22,7 +22,7 @@ jQuery( document ).ready( function( $ ) {
22
*/
23
function getExcludedCategoriesAdded() {
24
25
- const newCategoryIDs = $( '#woocommerce_facebookcommerce_fb_sync_exclude_categories' ).val();
26
let oldCategoryIDs = [];
27
28
if ( window.facebookAdsToolboxConfig && window.facebookAdsToolboxConfig.excludedCategoryIDs ) {
@@ -41,7 +41,7 @@ jQuery( document ).ready( function( $ ) {
41
*/
42
function getExcludedTagsAdded() {
43
44
- const newTagIDs = $( '#woocommerce_facebookcommerce_fb_sync_exclude_tags' ).val();
45
let oldTagIDs = [];
46
47
if ( window.facebookAdsToolboxConfig && window.facebookAdsToolboxConfig.excludedTagIDs ) {
@@ -134,14 +134,13 @@ jQuery( document ).ready( function( $ ) {
134
categoriesAdded = getExcludedCategoriesAdded(),
135
tagsAdded = getExcludedTagsAdded();
136
137
-
138
if ( categoriesAdded.length > 0 || tagsAdded.length > 0 ) {
139
140
$.post( facebook_for_woocommerce_settings_sync.ajax_url, {
141
- action: 'facebook_for_woocommerce_set_excluded_terms_prompt',
142
- security: facebook_for_woocommerce_settings_sync.set_excluded_terms_prompt_nonce,
143
categories: categoriesAdded,
144
- tags: tagsAdded,
145
}, function ( response ) {
146
147
if ( response && ! response.success ) {
@@ -156,12 +155,51 @@ jQuery( document ).ready( function( $ ) {
156
} );
157
158
// exclude products: submit form as normal
159
- $( '#facebook-for-woocommerce-confirm-settings-change' ).on( 'click', function () {
160
161
blockModal();
162
163
- submitSettingsSave = true;
164
- $submitButton.trigger( 'click' );
165
} );
166
167
} else {
22
*/
23
function getExcludedCategoriesAdded() {
24
25
+ const newCategoryIDs = $( '#woocommerce_facebookcommerce_excluded_product_category_ids' ).val();
26
let oldCategoryIDs = [];
27
28
if ( window.facebookAdsToolboxConfig && window.facebookAdsToolboxConfig.excludedCategoryIDs ) {
41
*/
42
function getExcludedTagsAdded() {
43
44
+ const newTagIDs = $( '#woocommerce_facebookcommerce_excluded_product_tag_ids' ).val();
45
let oldTagIDs = [];
46
47
if ( window.facebookAdsToolboxConfig && window.facebookAdsToolboxConfig.excludedTagIDs ) {
134
categoriesAdded = getExcludedCategoriesAdded(),
135
tagsAdded = getExcludedTagsAdded();
136
137
if ( categoriesAdded.length > 0 || tagsAdded.length > 0 ) {
138
139
$.post( facebook_for_woocommerce_settings_sync.ajax_url, {
140
+ action: 'facebook_for_woocommerce_set_excluded_terms_prompt',
141
+ security: facebook_for_woocommerce_settings_sync.set_excluded_terms_prompt_nonce,
142
categories: categoriesAdded,
143
+ tags: tagsAdded,
144
}, function ( response ) {
145
146
if ( response && ! response.success ) {
155
} );
156
157
// exclude products: submit form as normal
158
+ $( '.facebook-for-woocommerce-confirm-settings-change' ).on( 'click', function () {
159
160
blockModal();
161
162
+ // the user has an option to hide all the affected products from Facebook while adding the exclusion though
163
+ if ( $( this ).hasClass( 'hide-products' ) ) {
164
+
165
+ let product_cats = [], product_tags = [];
166
+
167
+ $( categoriesAdded ).each( function() {
168
+ product_cats.push( {
169
+ term_id: this,
170
+ taxonomy: 'product_cat',
171
+ visibility: false
172
+ } );
173
+ } );
174
+
175
+ $( tagsAdded ).each( function() {
176
+ product_tags.push( {
177
+ term_id: this,
178
+ taxonomy: 'product_tag',
179
+ visibility: false
180
+ } );
181
+ } );
182
+
183
+ $.post( facebook_for_woocommerce_settings_sync.ajax_url, {
184
+ action: 'facebook_for_woocommerce_set_products_visibility',
185
+ security: facebook_for_woocommerce_settings_sync.set_product_visibility_nonce,
186
+ product_categories: product_cats,
187
+ product_tags: product_tags,
188
+ }, function ( response ) {
189
+
190
+ if ( ! response || ! response.success ) {
191
+ console.log( response )
192
+ }
193
+
194
+ submitSettingsSave = true;
195
+ $submitButton.trigger( 'click' );
196
+ } );
197
+
198
+ } else {
199
+
200
+ submitSettingsSave = true;
201
+ $submitButton.trigger( 'click' );
202
+ }
203
} );
204
205
} else {
assets/js/admin/facebook-for-woocommerce-settings-sync.min.js CHANGED
@@ -1 +1 @@
1
- "use strict";jQuery(document).ready(function(r){if(0!==r('input[name="section"][value="facebookcommerce"]').closest("form").length){r('input[type="checkbox"].toggle-fields-group').on("change",function(e){r(this).hasClass("product-sync-field")?o(r(".product-sync-field").not(".toggle-fields-group"),r(this).is(":checked")):r(this).hasClass("messenger-field")?o(r(".messenger-field").not(".toggle-fields-group"),r(this).is(":checked")):r(this).hasClass("resync-schedule-field")&&o(r(".resync-schedule-field").not(".toggle-fields-group"),r(this).is(":checked"))}).trigger("change"),r("#woocommerce_facebookcommerce_scheduled_resync_hours, #woocommerce_facebookcommerce_scheduled_resync_minutes").on("input change keyup keydown keypress click",function(){var e=r(this).val();!isNaN(e)&&1===e.length&&e<10&&r(this).val(e.padStart(2,"0"))}).trigger("change"),r("textarea#woocommerce_facebookcommerce_messenger_greeting").on("focus change keyup keydown keypress",function(){var e=parseInt(window.facebookAdsToolboxConfig.messengerGreetingMaxCharacters,10),o=r(this).val().length,c=r("span.characters-counter"),s=c.find("span");c.html(o+" / "+e+"<br/>").append(s).css("display","block"),e<o?c.css("color","#DC3232").find("span").show():c.css("color","#999999").find("span").hide()});var l=!1;r(".woocommerce-save-button").on("click",function(e){if(l)return!0;e.preventDefault();var o,c,s,n,t=r(this),i=(s=r("#woocommerce_facebookcommerce_fb_sync_exclude_categories").val(),n=[],window.facebookAdsToolboxConfig&&window.facebookAdsToolboxConfig.excludedCategoryIDs&&(n=window.facebookAdsToolboxConfig.excludedCategoryIDs),r(s).not(n).get()),a=(o=r("#woocommerce_facebookcommerce_fb_sync_exclude_tags").val(),c=[],window.facebookAdsToolboxConfig&&window.facebookAdsToolboxConfig.excludedTagIDs&&(c=window.facebookAdsToolboxConfig.excludedTagIDs),r(o).not(c).get());0<i.length||0<a.length?r.post(facebook_for_woocommerce_settings_sync.ajax_url,{action:"facebook_for_woocommerce_set_excluded_terms_prompt",security:facebook_for_woocommerce_settings_sync.set_excluded_terms_prompt_nonce,categories:i,tags:a},function(e){e&&!e.success?(r("#wc-backbone-modal-dialog .modal-close").trigger("click"),new r.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:e.data}),r("#facebook-for-woocommerce-confirm-settings-change").on("click",function(){blockModal(),l=!0,t.trigger("click")})):(l=!0,t.trigger("click"))}):(l=!0,t.trigger("click"))})}function o(e,o){r(e).each(function(){var e=r(this);r(this).hasClass("wc-enhanced-select")&&(e=r(this).next("span.select2-container")),o?e.css("pointer-events","all").css("opacity","1.0"):e.css("pointer-events","none").css("opacity","0.4")})}});
1
+ "use strict";jQuery(document).ready(function(a){if(0!==a('input[name="section"][value="facebookcommerce"]').closest("form").length){a('input[type="checkbox"].toggle-fields-group').on("change",function(e){a(this).hasClass("product-sync-field")?o(a(".product-sync-field").not(".toggle-fields-group"),a(this).is(":checked")):a(this).hasClass("messenger-field")?o(a(".messenger-field").not(".toggle-fields-group"),a(this).is(":checked")):a(this).hasClass("resync-schedule-field")&&o(a(".resync-schedule-field").not(".toggle-fields-group"),a(this).is(":checked"))}).trigger("change"),a("#woocommerce_facebookcommerce_scheduled_resync_hours, #woocommerce_facebookcommerce_scheduled_resync_minutes").on("input change keyup keydown keypress click",function(){var e=a(this).val();!isNaN(e)&&1===e.length&&e<10&&a(this).val(e.padStart(2,"0"))}).trigger("change"),a("textarea#woocommerce_facebookcommerce_messenger_greeting").on("focus change keyup keydown keypress",function(){var e=parseInt(window.facebookAdsToolboxConfig.messengerGreetingMaxCharacters,10),o=a(this).val().length,c=a("span.characters-counter"),s=c.find("span");c.html(o+" / "+e+"<br/>").append(s).css("display","block"),e<o?c.css("color","#DC3232").find("span").show():c.css("color","#999999").find("span").hide()});var l=!1;a(".woocommerce-save-button").on("click",function(e){if(l)return!0;e.preventDefault();var o,c,s,t,i=a(this),n=(s=a("#woocommerce_facebookcommerce_excluded_product_category_ids").val(),t=[],window.facebookAdsToolboxConfig&&window.facebookAdsToolboxConfig.excludedCategoryIDs&&(t=window.facebookAdsToolboxConfig.excludedCategoryIDs),a(s).not(t).get()),r=(o=a("#woocommerce_facebookcommerce_excluded_product_tag_ids").val(),c=[],window.facebookAdsToolboxConfig&&window.facebookAdsToolboxConfig.excludedTagIDs&&(c=window.facebookAdsToolboxConfig.excludedTagIDs),a(o).not(c).get());0<n.length||0<r.length?a.post(facebook_for_woocommerce_settings_sync.ajax_url,{action:"facebook_for_woocommerce_set_excluded_terms_prompt",security:facebook_for_woocommerce_settings_sync.set_excluded_terms_prompt_nonce,categories:n,tags:r},function(e){e&&!e.success?(a("#wc-backbone-modal-dialog .modal-close").trigger("click"),new a.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:e.data}),a(".facebook-for-woocommerce-confirm-settings-change").on("click",function(){if(blockModal(),a(this).hasClass("hide-products")){var e=[],o=[];a(n).each(function(){e.push({term_id:this,taxonomy:"product_cat",visibility:!1})}),a(r).each(function(){o.push({term_id:this,taxonomy:"product_tag",visibility:!1})}),a.post(facebook_for_woocommerce_settings_sync.ajax_url,{action:"facebook_for_woocommerce_set_products_visibility",security:facebook_for_woocommerce_settings_sync.set_product_visibility_nonce,product_categories:e,product_tags:o},function(e){e&&e.success||console.log(e),l=!0,i.trigger("click")})}else l=!0,i.trigger("click")})):(l=!0,i.trigger("click"))}):(l=!0,i.trigger("click"))})}function o(e,o){a(e).each(function(){var e=a(this);a(this).hasClass("wc-enhanced-select")&&(e=a(this).next("span.select2-container")),o?e.css("pointer-events","all").css("opacity","1.0"):e.css("pointer-events","none").css("opacity","0.4")})}});
assets/js/facebook-settings.js CHANGED
@@ -10,17 +10,6 @@
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;
@@ -145,32 +134,39 @@ function fb_flush(){
145
);
146
}
147
148
function sync_confirm(verbose = null) {
149
- var msg = '';
150
switch (verbose) {
151
case 'fb_force_resync':
152
- msg = 'Your products will now be resynced with Facebook, ' +
153
- 'this may take some time.';
154
break;
155
case 'fb_test_product_sync':
156
- msg = 'Launch Test?';
157
break;
158
default:
159
- msg = 'Facebook for WooCommerce automatically syncs your products on ' +
160
- 'create/update. Are you sure you want to force product resync?\n\n' +
161
- 'This will query all published products and may take some time. ' +
162
- 'You only need to do this if your products are out of sync ' +
163
- 'or some of your products did not sync.';
164
- }
165
- if (confirm( msg )) {
166
- sync_all_products(
167
- window.facebookAdsToolboxConfig.feed.hasClientSideFeedUpload,
168
- verbose == 'fb_test_product_sync'
169
- );
170
window.fb_sync_start_time = new Date().getTime();
171
}
172
}
173
174
// Launch the confirm dialog immediately if the param is in the URL.
175
if (window.location.href.includes( "fb_force_resync" )) {
176
window.onload = function() { sync_confirm( "fb_force_resync" ); };
@@ -180,34 +176,77 @@ if (window.location.href.includes( "fb_force_resync" )) {
180
window.onload = function() { sync_confirm( "fb_test_product_sync" ); };
181
}
182
183
function sync_all_products($using_feed = false, $is_test = false) {
184
185
window.fb_connected = true;
186
sync_in_progress();
187
- if ($using_feed) {
188
window.facebookAdsToolboxConfig.feed.hasClientSideFeedUpload = true;
189
window.feed_upload = true;
190
ping_feed_status_queue();
191
- return $is_test ? ajax( 'ajax_test_sync_products_using_feed' )
192
- : ajax(
193
- 'ajax_sync_all_fb_products_using_feed',
194
- {
195
- "_ajax_nonce": wc_facebook_settings_jsx.nonce,
196
- },
197
- );
198
} else {
199
200
check_background_processor_status();
201
202
- return ajax(
203
- 'ajax_sync_all_fb_products',
204
- {
205
- "_ajax_nonce": wc_facebook_settings_jsx.nonce,
206
- }
207
- );
208
}
209
}
210
211
// Reset all state
212
function delete_all_settings(callback = null, failcallback = null) {
213
@@ -222,6 +261,16 @@ function delete_all_settings(callback = null, failcallback = null) {
222
get_page_id_box().value = '';
223
}
224
225
window.facebookAdsToolboxConfig.pixel.pixelId = '';
226
window.facebookAdsToolboxConfig.diaSettingId = '';
227
window.fb_connected = false;
@@ -320,66 +369,23 @@ function save_settings_and_sync(message) {
320
function sync_in_progress() {
321
322
// temporarily disable Manage connection and Sync products buttons
323
- jQuery( '#woocommerce-facebook-settings-manage-connection' ).css( 'pointer-events', 'none' );
324
- jQuery( '#woocommerce-facebook-settings-sync-products' ).css( 'pointer-events', 'none' );
325
326
// set products sync status
327
- if ( document.querySelector( '#sync_progress' ) ) {
328
- document.querySelector( '#sync_progress' ).innerHTML = 'Syncing... Keep this browser open until sync is complete.<span class="spinner is-active"></span>';
329
- }
330
- }
331
-
332
-
333
- function sync_not_in_progress(){
334
- // Reset to pre-setup state.
335
- if (document.querySelector( '#cta_button' )) {
336
- var cta_element = document.querySelector( '#cta_button' );
337
- cta_element.innerHTML = 'Create Ad';
338
- cta_element.style['font-size'] = '12px';
339
- cta_element.style.width = '60px';
340
- if (window.facebookAdsToolboxConfig.diaSettingId) {
341
- cta_element.onclick = function() {
342
- window.open(
343
- 'https://www.facebook.com/ads/dia/redirect/?settings_id=' +
344
- window.facebookAdsToolboxConfig.diaSettingId + '&version=2' +
345
- '&entry_point=admin_panel'
346
- );
347
- };
348
- } else {
349
- cta_element.style['pointer-events'] = 'none';
350
- }
351
- }
352
- if (document.querySelector( '#learnmore_button' )) {
353
- var learnmore_element = document.querySelector( '#learnmore_button' );
354
- if (window.facebookAdsToolboxConfig.diaSettingId) {
355
- learnmore_element.style.display = '';
356
- }
357
- }
358
- if (document.querySelector( '#setup_h1' )) {
359
- document.querySelector( '#setup_h1' ).innerHTML =
360
- 'Reach the right people and sell more products';
361
- }
362
- if (document.querySelector( '#setup_l1' )) {
363
- document.querySelector( '#setup_l1' ).innerHTML =
364
- 'Create an ad in a few steps';
365
- }
366
- if (document.querySelector( '#setup_l2' )) {
367
- document.querySelector( '#setup_l2' ).innerHTML =
368
- 'Use built-in best practice for online sales';
369
- }
370
- if (document.querySelector( '#setup_l3' )) {
371
- document.querySelector( '#setup_l3' ).innerHTML =
372
- 'Get reporting on sales and revenue';
373
- }
374
375
// enable Manage connection and Sync products buttons when sync is complete
376
- jQuery( '#woocommerce-facebook-settings-manage-connection' ).css( 'pointer-events', 'auto' );
377
- jQuery( '#woocommerce-facebook-settings-sync-products' ).css( 'pointer-events', 'auto' );
378
379
// Remove sync progress.
380
- if (document.querySelector( '#sync_progress' )) {
381
- document.querySelector( '#sync_progress' ).innerHTML = '';
382
- }
383
}
384
385
@@ -499,11 +505,15 @@ function setAccessTokenAndPageId(message) {
499
}
500
}
501
502
- function setMsgerChatSetup(data) {
503
- if (data.hasOwnProperty( 'is_messenger_chat_plugin_enabled' )) {
504
- settings.is_messenger_chat_plugin_enabled =
505
- data.is_messenger_chat_plugin_enabled;
506
}
507
if (data.hasOwnProperty( 'facebook_jssdk_version' )) {
508
settings.facebook_jssdk_version =
509
data.facebook_jssdk_version;
@@ -512,20 +522,29 @@ function setMsgerChatSetup(data) {
512
settings.fb_page_id = data.page_id;
513
}
514
515
- if (data.hasOwnProperty( 'customization' )) {
516
- var customization = data.customization;
517
518
- if (customization.hasOwnProperty( 'greetingTextCode' )) {
519
- settings.msger_chat_customization_greeting_text_code =
520
- customization.greetingTextCode;
521
}
522
- if (customization.hasOwnProperty( 'locale' )) {
523
- settings.msger_chat_customization_locale =
524
- customization.locale;
525
}
526
- if (customization.hasOwnProperty( 'themeColorCode' )) {
527
- settings.msger_chat_customization_theme_color_code =
528
- customization.themeColorCode;
529
}
530
}
531
}
@@ -653,13 +672,12 @@ function ping_feed_status_queue(count = 0) {
653
);
654
}
655
656
- function product_sync_complete(sync_progress_element) {
657
658
sync_not_in_progress();
659
660
- if (sync_progress_element) {
661
- sync_progress_element.innerHTML = '';
662
- }
663
clearInterval( window.fb_pings );
664
}
665
@@ -679,7 +697,9 @@ function check_queues() {
679
clearInterval( window.fb_pings );
680
return;
681
}
682
- var sync_progress_element = document.querySelector( '#sync_progress' );
683
var res = parse_response_check_connection( response );
684
if ( !res ) {
685
if ( fb_sync_no_response_count++ > 5 ) {
@@ -697,13 +717,23 @@ function check_queues() {
697
698
var processing = !!res.processing; // explicit boolean conversion
699
var remaining = res.remaining;
700
if ( processing ) {
701
- if ( sync_progress_element ) {
702
- sync_progress_element.innerHTML = '<strong>Progress:</strong> ' + remaining + ' item' + ( remaining > 1 ? 's' : '' ) + ' remaining.<span class="spinner is-active"></span>';
703
}
704
if ( remaining === 0 ) {
705
- product_sync_complete( sync_progress_element );
706
}
707
} else {
708
// Not processing, none remaining. Either long complete, or just completed
709
if ( window.fb_sync_start_time && res.request_time ) {
@@ -716,7 +746,7 @@ function check_queues() {
716
}
717
718
if ( remaining === 0 ) {
719
- product_sync_complete( sync_progress_element );
720
}
721
}
722
}
@@ -745,8 +775,9 @@ function check_feed_upload_queue(check_num) {
745
"_ajax_nonce": wc_facebook_settings_jsx.nonce,
746
},
747
function(response) {
748
- var sync_progress_element = document.querySelector( '#sync_progress' );
749
- var res = parse_response_check_connection( response );
750
751
clearInterval( window.fb_feed_pings );
752
@@ -758,20 +789,22 @@ function check_feed_upload_queue(check_num) {
758
if (window.is_test) {
759
display_test_result();
760
} else {
761
- product_sync_complete( sync_progress_element );
762
}
763
break;
764
case 'in progress':
765
- if (sync_progress_element) {
766
- sync_progress_element.innerHTML = 'Syncing... Keep this browser open until sync is complete.<span class="spinner is-active"></span>';
767
- }
768
ping_feed_status_queue( check_num + 1 );
769
- break;
770
771
default:
772
- if ( sync_progress_element ) {
773
- sync_progress_element.innerHTML = '<strong>Something wrong when uploading, please try again.</strong>';
774
- }
775
776
window.feed_upload = false;
777
if (window.is_test) {
@@ -790,8 +823,9 @@ function display_test_result() {
790
"_ajax_nonce": wc_facebook_settings_jsx.nonce
791
},
792
function(response) {
793
var sync_complete_element = document.querySelector( '#sync_complete' );
794
- var sync_progress_element = document.querySelector( '#sync_progress' );
795
var res = parse_response_check_connection( response );
796
if (res) {
797
var status = res.pass;
@@ -800,31 +834,28 @@ function display_test_result() {
800
sync_not_in_progress();
801
if (sync_complete_element) {
802
sync_complete_element.style.display = '';
803
- sync_complete_element.innerHTML =
804
- '<strong>Status: </strong>Test Pass.';
805
- }
806
- if (sync_progress_element) {
807
- sync_progress_element.innerHTML = '';
808
}
809
window.is_test = false;
810
break;
811
case 'in progress':
812
- if (sync_progress_element) {
813
- sync_progress_element.innerHTML =
814
- '<strong>Integration test in progress...</strong>';
815
- }
816
ping_feed_status_queue();
817
- break;
818
default:
819
window.debug_info = res.debug_info + '<br/>' + res.stack_trace;
820
if (sync_complete_element) {
821
sync_complete_element.style.display = '';
822
- sync_complete_element.innerHTML =
823
- '<strong>Status: </strong>Test Fail.';
824
- }
825
- if (sync_progress_element) {
826
- sync_progress_element.innerHTML = '';
827
}
828
if (document.querySelector( '#debug_info' )) {
829
document.querySelector( '#debug_info' ).style.display = '';
830
}
10
var fb_sync_no_response_count = 0;
11
var fb_show_advanced_options = false;
12
13
14
function openPopup() {
15
var width = 1153;
134
);
135
}
136
137
+
138
+ /**
139
+ * Shows a confirm dialog and starts product sync if the user selectes OK.
140
+ *
141
+ * @param {String} verbose an identifier for the confirmation message to display
142
+ */
143
function sync_confirm(verbose = null) {
144
+
145
+ let msg = '';
146
+
147
switch (verbose) {
148
+
149
case 'fb_force_resync':
150
+ msg = facebook_for_woocommerce_settings_sync.i18n.confirm_resync;
151
break;
152
+
153
case 'fb_test_product_sync':
154
+ msg = facebook_for_woocommerce_settings_sync.i18n.confirm_sync_test;
155
break;
156
+
157
default:
158
+ msg = facebook_for_woocommerce_settings_sync.i18n.confirm_sync;
159
+ }
160
+
161
+ if ( confirm( msg ) ) {
162
+
163
+ sync_all_products( window.facebookAdsToolboxConfig.feed.hasClientSideFeedUpload, verbose == 'fb_test_product_sync' );
164
+
165
window.fb_sync_start_time = new Date().getTime();
166
}
167
}
168
169
+
170
// Launch the confirm dialog immediately if the param is in the URL.
171
if (window.location.href.includes( "fb_force_resync" )) {
172
window.onload = function() { sync_confirm( "fb_force_resync" ); };
176
window.onload = function() { sync_confirm( "fb_test_product_sync" ); };
177
}
178
179
+
180
+ /**
181
+ * Sends Ajax request to the backend to initiate product sync.
182
+ *
183
+ * @param {boolean} feed whether products should be synced using feed or not
184
+ * @param {boolean} test whether this is a sync test
185
+ */
186
function sync_all_products($using_feed = false, $is_test = false) {
187
188
window.fb_connected = true;
189
sync_in_progress();
190
+
191
+ let data = {};
192
+
193
+ if ( $using_feed ) {
194
+
195
window.facebookAdsToolboxConfig.feed.hasClientSideFeedUpload = true;
196
window.feed_upload = true;
197
+
198
ping_feed_status_queue();
199
+
200
+ if ( $is_test ) {
201
+
202
+ data = { action: 'ajax_test_sync_products_using_feed' };
203
+
204
+ } else {
205
+
206
+ data = {
207
+ action: 'ajax_sync_all_fb_products_using_feed',
208
+ _ajax_nonce: wc_facebook_settings_jsx.nonce,
209
+ };
210
+
211
+ }
212
+
213
} else {
214
215
check_background_processor_status();
216
217
+ data = {
218
+ action: 'ajax_sync_all_fb_products',
219
+ _ajax_nonce: wc_facebook_settings_jsx.nonce,
220
+ };
221
}
222
+
223
+ jQuery.post( ajaxurl, data ).then( function( response ) {
224
+
225
+ // something is wrong if we are syncing products using feed and the response is empty or indicates a failure
226
+ // we ignore empty responses if using the background processor because in those cases the request does not return a response when the operation is successful
227
+ if ( ( ! response && $using_feed ) || ( response && false === response.success ) ) {
228
+
229
+ // no need to check the queue or upload status
230
+ clearInterval( window.fb_pings );
231
+ clearInterval( window.fb_feed_pings );
232
+
233
+ // enable Manage connection and Sync products buttons when sync stops
234
+ jQuery( '#woocommerce-facebook-settings-manage-connection, #woocommerce-facebook-settings-sync-products' ).css( 'pointer-events', 'auto' );
235
+
236
+ let message;
237
+
238
+ if ( response && response.data && response.data.error ) {
239
+ message = response.data.error;
240
+ } else {
241
+ message = facebook_for_woocommerce_settings_sync.i18n.general_error;
242
+ }
243
+
244
+ $( '#sync_progress' ).show().html( '<span style="color: #DC3232">' + message + '</span>' );
245
+ }
246
+ } );
247
}
248
249
+
250
// Reset all state
251
function delete_all_settings(callback = null, failcallback = null) {
252
261
get_page_id_box().value = '';
262
}
263
264
+ // reset messenger settings to their default values
265
+ jQuery( '#woocommerce_facebookcommerce_enable_messenger' ).prop( 'checked', false ).trigger( 'change' );
266
+
267
+ jQuery( '.messenger-field' ).each( function () {
268
+
269
+ if ( typeof $( this ).data( 'default' ) !== 'undefined' ) {
270
+ $( this ).val( $( this ).data( 'default' ) ).trigger( 'change' );
271
+ }
272
+ } );
273
+
274
window.facebookAdsToolboxConfig.pixel.pixelId = '';
275
window.facebookAdsToolboxConfig.diaSettingId = '';
276
window.fb_connected = false;
369
function sync_in_progress() {
370
371
// temporarily disable Manage connection and Sync products buttons
372
+ jQuery( '#woocommerce-facebook-settings-manage-connection, #woocommerce-facebook-settings-sync-products' ).css( 'pointer-events', 'none' );
373
374
// set products sync status
375
+ jQuery( '#sync_progress' ).show().html( facebook_for_woocommerce_settings_sync.i18n.sync_in_progress );
376
+ }
377
+
378
+
379
+ /**
380
+ * Hides sync progress and enable Manage connection and Sync products buttons.
381
+ */
382
+ function sync_not_in_progress() {
383
384
// enable Manage connection and Sync products buttons when sync is complete
385
+ jQuery( '#woocommerce-facebook-settings-manage-connection, #woocommerce-facebook-settings-sync-products' ).css( 'pointer-events', 'auto' );
386
387
// Remove sync progress.
388
+ jQuery( '#sync_progress' ).empty().hide();
389
}
390
391
505
}
506
}
507
508
+ function setMsgerChatSetup( data ) {
509
+
510
+ if ( data.hasOwnProperty( 'is_messenger_chat_plugin_enabled' ) ) {
511
+
512
+ settings.is_messenger_chat_plugin_enabled = data.is_messenger_chat_plugin_enabled;
513
+
514
+ jQuery( '#woocommerce_facebookcommerce_enable_messenger' ).prop( 'checked', data.is_messenger_chat_plugin_enabled ).trigger( 'change' );
515
}
516
+
517
if (data.hasOwnProperty( 'facebook_jssdk_version' )) {
518
settings.facebook_jssdk_version =
519
data.facebook_jssdk_version;
522
settings.fb_page_id = data.page_id;
523
}
524
525
+ if ( data.hasOwnProperty( 'customization' ) ) {
526
+
527
+ const customization = data.customization;
528
+
529
+ if ( customization.hasOwnProperty( 'greetingTextCode' ) ) {
530
+
531
+ settings.msger_chat_customization_greeting_text_code = customization.greetingTextCode;
532
533
+ jQuery( '#woocommerce_facebookcommerce_messenger_greeting' ).val( customization.greetingTextCode ).trigger( 'change' );
534
}
535
+
536
+ if ( customization.hasOwnProperty( 'locale' ) ) {
537
+
538
+ settings.msger_chat_customization_locale = customization.locale;
539
+
540
+ jQuery( '#woocommerce_facebookcommerce_messenger_locale' ).val( customization.locale ).trigger( 'change' );
541
}
542
+
543
+ if ( customization.hasOwnProperty( 'themeColorCode' ) ) {
544
+
545
+ settings.msger_chat_customization_theme_color_code = customization.themeColorCode;
546
+
547
+ jQuery( '#woocommerce_facebookcommerce_messenger_color_hex' ).val( customization.themeColorCode ).trigger( 'change' );
548
}
549
}
550
}
672
);
673
}
674
675
+ function product_sync_complete( $sync_progress_element ) {
676
677
sync_not_in_progress();
678
679
+ $sync_progress_element.empty().hide();
680
+
681
clearInterval( window.fb_pings );
682
}
683
697
clearInterval( window.fb_pings );
698
return;
699
}
700
+
701
+ const $sync_progress_element = jQuery( '#sync_progress' );
702
+
703
var res = parse_response_check_connection( response );
704
if ( !res ) {
705
if ( fb_sync_no_response_count++ > 5 ) {
717
718
var processing = !!res.processing; // explicit boolean conversion
719
var remaining = res.remaining;
720
+
721
if ( processing ) {
722
+
723
+ let message = '';
724
+
725
+ if ( 1 === remaining ) {
726
+ message = facebook_for_woocommerce_settings_sync.i18n.sync_remaining_items_singular;
727
+ } else {
728
+ message = facebook_for_woocommerce_settings_sync.i18n.sync_remaining_items_plural;
729
}
730
+
731
+ $sync_progress_element.show().html( message.replace( '{count}', remaining ) );
732
+
733
if ( remaining === 0 ) {
734
+ product_sync_complete( $sync_progress_element );
735
}
736
+
737
} else {
738
// Not processing, none remaining. Either long complete, or just completed
739
if ( window.fb_sync_start_time && res.request_time ) {
746
}
747
748
if ( remaining === 0 ) {
749
+ product_sync_complete( $sync_progress_element );
750
}
751
}
752
}
775
"_ajax_nonce": wc_facebook_settings_jsx.nonce,
776
},
777
function(response) {
778
+ const $sync_progress_element = jQuery( '#sync_progress' );
779
+
780
+ var res = parse_response_check_connection( response );
781
782
clearInterval( window.fb_feed_pings );
783
789
if (window.is_test) {
790
display_test_result();
791
} else {
792
+ product_sync_complete( $sync_progress_element );
793
}
794
break;
795
case 'in progress':
796
+
797
+ $sync_progress_element.show().html( facebook_for_woocommerce_settings_sync.i18n.sync_in_progress );
798
+
799
ping_feed_status_queue( check_num + 1 );
800
+ break;
801
802
default:
803
+
804
+ // enable Manage connection and Sync products buttons when sync stops
805
+ jQuery( '#woocommerce-facebook-settings-manage-connection, #woocommerce-facebook-settings-sync-products' ).css( 'pointer-events', 'auto' );
806
+
807
+ $( '#sync_progress' ).show().html( '<span style="color: #DC3232">' + facebook_for_woocommerce_settings_sync.i18n.feed_upload_error + '</span>' );
808
809
window.feed_upload = false;
810
if (window.is_test) {
823
"_ajax_nonce": wc_facebook_settings_jsx.nonce
824
},
825
function(response) {
826
+ const $sync_progress_element = jQuery( '#sync_progress' );
827
+
828
var sync_complete_element = document.querySelector( '#sync_complete' );
829
var res = parse_response_check_connection( response );
830
if (res) {
831
var status = res.pass;
834
sync_not_in_progress();
835
if (sync_complete_element) {
836
sync_complete_element.style.display = '';
837
+ sync_complete_element.innerHTML = facebook_for_woocommerce_settings_sync.i18n.integration_test_sucessful;
838
}
839
+
840
+ $sync_progress_element.empty().hide();
841
+
842
window.is_test = false;
843
break;
844
case 'in progress':
845
+
846
+ $sync_progress_element.show().html( facebook_for_woocommerce_settings_sync.i18n.integration_test_in_progress );
847
+
848
ping_feed_status_queue();
849
+ break;
850
default:
851
window.debug_info = res.debug_info + '<br/>' + res.stack_trace;
852
if (sync_complete_element) {
853
sync_complete_element.style.display = '';
854
+ sync_complete_element.innerHTML = facebook_for_woocommerce_settings_sync.i18n.integration_test_failed;
855
}
856
+
857
+ $sync_progress_element.empty().hide();
858
+
859
if (document.querySelector( '#debug_info' )) {
860
document.querySelector( '#debug_info' ).style.display = '';
861
}
assets/js/facebook-settings.min.js CHANGED
@@ -1 +1 @@
1
- "use strict";var fb_sync_no_response_count=0,fb_show_advanced_options=!1;function toggleAdvancedOptions(){var e=document.getElementById("fbAdvancedOptions");fb_show_advanced_options?(e.style.display="none",document.getElementById("fbAdvancedOptionsText").innerHTML="Show Advanced Settings"):(e.style.display="block",document.getElementById("fbAdvancedOptionsText").innerHTML="Hide Advanced Settings"),fb_show_advanced_options=!fb_show_advanced_options}function openPopup(){var e,o=screen.height/2-404,n=screen.width/2-576.5;window.originParam=window.location.protocol+"//"+window.location.host,window.facebookAdsToolboxConfig.popupOrigin.includes("staticxx")&&(window.facebookAdsToolboxConfig.popupOrigin="https://www.facebook.com/"),window.facebookAdsToolboxConfig.popupOrigin=prepend_protocol(window.facebookAdsToolboxConfig.popupOrigin),e=window.facebookAdsToolboxConfig.popupOrigin;var t=window.open(e+"/login.php?display=popup&next="+encodeURIComponent(e+"/ads/dia?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=1153","height=808","top="+o,"left="+n].join(","));return function(e,o){t.postMessage({type:e,params:o},window.facebookAdsToolboxConfig.popupOrigin)}}function prepend_protocol(e){return 0===e.indexOf("//www.")&&(e="https:"+e),e}function get_pixel_id_box(){return document.querySelector("#woocommerce_facebookcommerce_facebook_pixel_id")}function get_pixel_use_pii_id_box(){return document.querySelector("#woocommerce_facebookcommerce_enable_advanced_matching")}function get_page_id_box(){return document.querySelector("#woocommerce_facebookcommerce_facebook_page_id")}function ajax(e){var o=1<arguments.length&&void 0!==arguments[1]?arguments[1]:null,n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null,t=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null,s=Object.assign({},{action:e},o);jQuery.post(ajaxurl,s,function(e){n&&n(e)}).fail(function(e){t&&t(e)})}var settings={facebook_for_woocommerce:1},pixel_settings={facebook_for_woocommerce:1};function facebookConfig(){window.sendToFacebook=openPopup(),window.diaConfig={clientSetup:window.facebookAdsToolboxConfig}}function fb_flush(){return console.log("Removing all FBIDs from all products!"),ajax("ajax_reset_all_fb_products",{_ajax_nonce:wc_facebook_settings_jsx.nonce},null,function(){console.log("Failed to reset all FB products")})}function sync_confirm(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null,o="";switch(e){case"fb_force_resync":o="Your products will now be resynced with Facebook, this may take some time.";break;case"fb_test_product_sync":o="Launch Test?";break;default:o="Facebook for WooCommerce automatically syncs your products on create/update. Are you sure you want to force product resync?\n\nThis will query all published products and may take some time. You only need to do this if your products are out of sync or some of your products did not sync."}confirm(o)&&(sync_all_products(window.facebookAdsToolboxConfig.feed.hasClientSideFeedUpload,"fb_test_product_sync"==e),window.fb_sync_start_time=(new Date).getTime())}function sync_all_products(){var e=0<arguments.length&&void 0!==arguments[0]&&arguments[0],o=1<arguments.length&&void 0!==arguments[1]&&arguments[1];return window.fb_connected=!0,sync_in_progress(),e?(window.facebookAdsToolboxConfig.feed.hasClientSideFeedUpload=!0,window.feed_upload=!0,ping_feed_status_queue(),o?ajax("ajax_test_sync_products_using_feed"):ajax("ajax_sync_all_fb_products_using_feed",{_ajax_nonce:wc_facebook_settings_jsx.nonce})):(check_background_processor_status(),ajax("ajax_sync_all_fb_products",{_ajax_nonce:wc_facebook_settings_jsx.nonce}))}function delete_all_settings(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null,o=1<arguments.length&&void 0!==arguments[1]?arguments[1]:null;return get_pixel_id_box()&&(get_pixel_id_box().value=""),get_pixel_use_pii_id_box()&&(get_pixel_use_pii_id_box().checked=!1),get_page_id_box()&&(get_page_id_box().value=""),window.facebookAdsToolboxConfig.pixel.pixelId="",window.facebookAdsToolboxConfig.diaSettingId="",window.fb_connected=!1,not_connected(),console.log("Deleting all settings and removing all FBIDs!"),ajax("ajax_delete_fb_settings",{_ajax_nonce:wc_facebook_settings_jsx.nonce},e,o)}function save_settings(){var o=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null,n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:null,e=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;(e=e||settings)._ajax_nonce=wc_facebook_settings_jsx.nonce,ajax("ajax_save_fb_settings",e,function(e){o&&o(e)},function(e){n&&n(e)})}function save_settings_for_plugin(o,n){save_settings(function(e){e&&e.includes("settings_saved")?(console.log(e),o(e)):(console.log("Fail response on save_settings_and_sync"),n(e))},function(e){console.log("Ajax error while saving settings:"+JSON.stringify(e)),n(e)})}function save_settings_and_sync(o){"api_key"in settings&&save_settings(function(e){e&&e.includes("settings_saved")?(console.log(e),window.sendToFacebook("ack set pixel",o.params),window.sendToFacebook("ack set page access token",o.params),window.sendToFacebook("ack set merchant settings",o.params),sync_all_products(!0)):(window.sendToFacebook("fail save_settings",e),console.log("Fail response on save_settings_and_sync"))},function(e){console.log("Ajax error while saving settings:"+JSON.stringify(e)),window.sendToFacebook("fail save_settings_ajax",JSON.stringify(e))})}function sync_in_progress(){jQuery("#woocommerce-facebook-settings-manage-connection").css("pointer-events","none"),jQuery("#woocommerce-facebook-settings-sync-products").css("pointer-events","none"),document.querySelector("#sync_progress")&&(document.querySelector("#sync_progress").innerHTML='Syncing... Keep this browser open until sync is complete.<span class="spinner is-active"></span>')}function sync_not_in_progress(){if(document.querySelector("#cta_button")){var e=document.querySelector("#cta_button");e.innerHTML="Create Ad",e.style["font-size"]="12px",e.style.width="60px",window.facebookAdsToolboxConfig.diaSettingId?e.onclick=function(){window.open("https://www.facebook.com/ads/dia/redirect/?settings_id="+window.facebookAdsToolboxConfig.diaSettingId+"&version=2&entry_point=admin_panel")}:e.style["pointer-events"]="none"}if(document.querySelector("#learnmore_button")){var o=document.querySelector("#learnmore_button");window.facebookAdsToolboxConfig.diaSettingId&&(o.style.display="")}document.querySelector("#setup_h1")&&(document.querySelector("#setup_h1").innerHTML="Reach the right people and sell more products"),document.querySelector("#setup_l1")&&(document.querySelector("#setup_l1").innerHTML="Create an ad in a few steps"),document.querySelector("#setup_l2")&&(document.querySelector("#setup_l2").innerHTML="Use built-in best practice for online sales"),document.querySelector("#setup_l3")&&(document.querySelector("#setup_l3").innerHTML="Get reporting on sales and revenue"),jQuery("#woocommerce-facebook-settings-manage-connection").css("pointer-events","auto"),jQuery("#woocommerce-facebook-settings-sync-products").css("pointer-events","auto"),document.querySelector("#sync_progress")&&(document.querySelector("#sync_progress").innerHTML="")}function not_connected(){jQuery("#fbsetup").show(),jQuery("#integration-settings").hide(),jQuery(".woocommerce-save-button").hide()}function addAnEventListener(e,o,n){"addEventListener"in e?e.addEventListener(o,n,!1):"attachEvent"in e&&e.attachEvent("on"+o,n)}function setMerchantSettings(e){if(!e.params.setting_id)return console.error("Facebook Extension Error: got no setting_id",e.params),void window.sendToFacebook("fail set merchant settings",e.params);settings.external_merchant_settings_id=e.params.setting_id,window.facebookAdsToolboxConfig.diaSettingId=e.params.setting_id}function setCatalog(e){if(!e.params.catalog_id)return console.error("Facebook Extension Error: got no catalog_id",e.params),void window.sendToFacebook("fail set catalog",e.params);settings.product_catalog_id=e.params.catalog_id,window.sendToFacebook("ack set catalog",e.params)}function setPixel(o){if(!o.params.pixel_id)return console.error("Facebook Ads Extension Error: got no pixel_id",o.params),void window.sendToFacebook("fail set pixel",o.params);get_pixel_id_box()&&(get_pixel_id_box().value=o.params.pixel_id),settings.pixel_id=o.params.pixel_id,pixel_settings.pixel_id=settings.pixel_id,void 0!==o.params.pixel_use_pii&&(get_pixel_use_pii_id_box()&&(get_pixel_use_pii_id_box().checked=!!o.params.pixel_use_pii),settings.pixel_use_pii=o.params.pixel_use_pii,pixel_settings.pixel_use_pii=settings.pixel_use_pii),save_settings(function(e){e&&e.includes("settings_saved")&&window.sendToFacebook("ack set pixel",o.params)},function(e){console.log(e),window.sendToFacebook("fail set pixel",e)},pixel_settings)}function genFeed(e){}function setAccessTokenAndPageId(e){if(!e.params.page_token)return console.error("Facebook Ads Extension Error: got no page_token",e.params),void window.sendToFacebook("fail set page access token",e.params);get_page_id_box()&&(get_page_id_box().value=e.params.page_id),settings.api_key=e.params.page_token,settings.page_id=e.params.page_id,window.facebookAdsToolboxConfig.tokenExpired=!1,document.querySelector("#connection-message-invalid")&&(document.querySelector("#connection-message-invalid").style.display="none"),document.querySelector("#connection-message-refresh")&&(document.querySelector("#connection-message-refresh").style.display="block")}function setMsgerChatSetup(e){if(e.hasOwnProperty("is_messenger_chat_plugin_enabled")&&(settings.is_messenger_chat_plugin_enabled=e.is_messenger_chat_plugin_enabled),e.hasOwnProperty("facebook_jssdk_version")&&(settings.facebook_jssdk_version=e.facebook_jssdk_version),e.hasOwnProperty("page_id")&&(settings.fb_page_id=e.page_id),e.hasOwnProperty("customization")){var o=e.customization;o.hasOwnProperty("greetingTextCode")&&(settings.msger_chat_customization_greeting_text_code=o.greetingTextCode),o.hasOwnProperty("locale")&&(settings.msger_chat_customization_locale=o.locale),o.hasOwnProperty("themeColorCode")&&(settings.msger_chat_customization_theme_color_code=o.themeColorCode)}}function iFrameListener(o){var e=o.origin||o.originalEvent.origin;switch(e!=window.facebookAdsToolboxConfig.popupOrigin&&urlFromSameDomain(e,window.facebookAdsToolboxConfig.popupOrigin)&&(window.facebookAdsToolboxConfig.popupOrigin=e),o.data.type){case"reset":delete_all_settings(function(e){e&&o.data.params?"Settings Deleted"===e?window.sendToFacebook("ack reset",o.data.params):(console.log(e),alert(e)):console.log("Got no response from delete_all_settings")},function(e){console.error(e)});break;case"get dia settings":window.sendToFacebook("dia settings",window.diaConfig);break;case"set merchant settings":setMerchantSettings(o.data);break;case"set catalog":setCatalog(o.data);break;case"set pixel":setPixel(o.data);break;case"gen feed":genFeed();break;case"set page access token":setAccessTokenAndPageId(o.data),save_settings_and_sync(o.data),jQuery("#fbsetup").hide(),jQuery("#integration-settings").show(),jQuery(".woocommerce-save-button").show();break;case"set msger chat":setMsgerChatSetup(o.data.params),save_settings_for_plugin(function(e){window.sendToFacebook("ack msger chat",o.data)},function(e){window.sendToFacebook("fail ack msger chat",o.data)})}}function urlFromSameDomain(e,o){if(!e.startsWith("http")||!o.startsWith("http"))return!1;var n=parseURL(e),t=parseURL(o),s=n.host.replace(/^\w+\./,"www."),i=t.host.replace(/^\w+\./,"www.");return n.protocol===t.protocol&&s===i}function parseURL(e){var o=document.createElement("a");return o.href=e,o}function check_background_processor_status(){window.facebookAdsToolboxConfig.feed.hasClientSideFeedUpload||(clearInterval(window.fb_pings),window.fb_pings=setInterval(function(){console.log("Pinging queue..."),check_queues()},1e4))}function ping_feed_status_queue(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:0;clearInterval(window.fb_feed_pings),window.fb_feed_pings=setInterval(function(){console.log("Pinging feed uploading queue..."),check_feed_upload_queue(e)},3e4*(1<<e))}function product_sync_complete(e){sync_not_in_progress(),e&&(e.innerHTML=""),clearInterval(window.fb_pings)}function check_queues(){ajax("ajax_fb_background_check_queue",{request_time:(new Date).getTime(),_ajax_nonce:wc_facebook_settings_jsx.nonce},function(e){if(window.feed_upload)clearInterval(window.fb_pings);else{var o=document.querySelector("#sync_progress"),n=parse_response_check_connection(e);if(n){if(fb_sync_no_response_count=0,n){n.background||(console.log("No background sync found, disabling pings"),clearInterval(window.fb_pings));var t=!!n.processing,s=n.remaining;if(t)o&&(o.innerHTML="<strong>Progress:</strong> "+s+" item"+(1<s?"s":"")+' remaining.<span class="spinner is-active"></span>'),0===s&&product_sync_complete(o);else{if(window.fb_sync_start_time&&n.request_time){var i=new Date(parseInt(n.request_time));if(window.fb_sync_start_time>i)return void console.log("OLD PING")}0===s&&product_sync_complete(o)}}}else 5<fb_sync_no_response_count++&&clearInterval(window.fb_pings)}})}function parse_response_check_connection(e){if(e){console.log(e);var o=e.substring(e.indexOf("{"));return(o=JSON.parse(o)).connected||window.fb_connected?o:(not_connected(),null)}return null}function check_feed_upload_queue(t){ajax("ajax_check_feed_upload_status",{_ajax_nonce:wc_facebook_settings_jsx.nonce},function(e){var o=document.querySelector("#sync_progress"),n=parse_response_check_connection(e);if(clearInterval(window.fb_feed_pings),n)switch(n.status){case"complete":window.feed_upload=!1,window.is_test?display_test_result():product_sync_complete(o);break;case"in progress":o&&(o.innerHTML='Syncing... Keep this browser open until sync is complete.<span class="spinner is-active"></span>'),ping_feed_status_queue(t+1);break;default:o&&(o.innerHTML="<strong>Something wrong when uploading, please try again.</strong>"),window.feed_upload=!1,window.is_test&&display_test_result()}})}function display_test_result(){ajax("ajax_display_test_result",{_ajax_nonce:wc_facebook_settings_jsx.nonce},function(e){var o=document.querySelector("#sync_complete"),n=document.querySelector("#sync_progress"),t=parse_response_check_connection(e);if(t)switch(t.pass){case"true":sync_not_in_progress(),o&&(o.style.display="",o.innerHTML="<strong>Status: </strong>Test Pass."),n&&(n.innerHTML=""),window.is_test=!1;break;case"in progress":n&&(n.innerHTML="<strong>Integration test in progress...</strong>"),ping_feed_status_queue();break;default:window.debug_info=t.debug_info+"<br/>"+t.stack_trace,o&&(o.style.display="",o.innerHTML="<strong>Status: </strong>Test Fail."),n&&(n.innerHTML=""),document.querySelector("#debug_info")&&(document.querySelector("#debug_info").style.display=""),window.is_test=!1}})}function show_debug_info(){var e=document.querySelector("#stack_trace");e&&(e.innerHTML=window.debug_info),document.querySelector("#debug_info")&&(document.querySelector("#debug_info").style.display="none"),window.debug_info=""}function fbe_init_nux_messages(){var r=window.jQuery;r(function(){r.each(r(".nux-message"),function(e,o){var n=r(o),t=n.data("target"),s=r("#"+t),i=s.position(),a=s.height()/2,c=s.outerWidth();n.css({top:Math.ceil(i.top+a)+"px",left:Math.ceil(i.left+c)+"px",display:"block"}),r(".nux-message-close-btn",n).click(function(){r(o).hide()})})})}function saveAutoSyncSchedule(){var e=document.getElementsByClassName("autosyncCheck")[0].checked,o=document.getElementsByClassName("autosyncTime")[0],n=(document.getElementsByClassName("autosyncSaveButton")[0],document.getElementsByClassName("autosyncSavedNotice")[0]);e?(o.removeAttribute("disabled"),n.style.transition="",n.style.opacity=1,setTimeout(function(){n.style.opacity=0,n.style.transition="opacity 5s"},3e3)):o.setAttribute("disabled",!0),ajax("ajax_schedule_force_resync",{enabled:e?1:0,time:o.value,_ajax_nonce:wc_facebook_settings_jsx.nonce})}function syncShortDescription(){var e=document.getElementsByClassName("syncShortDescription")[0].checked;ajax("ajax_update_fb_option",{option:"fb_sync_short_description",option_value:e?1:0,_ajax_nonce:wc_facebook_settings_jsx.nonce},null,function(){document.getElementsByClassName("syncShortDescription")[0].checked=!e,console.log("Failed to sync Short Description")})}window.location.href.includes("fb_force_resync")?window.onload=function(){sync_confirm("fb_force_resync")}:window.location.href.includes("fb_test_product_sync")&&(window.is_test=!0,window.onload=function(){sync_confirm("fb_test_product_sync")}),addAnEventListener(window,"message",iFrameListener),jQuery(document).ready(function(e){check_background_processor_status(),e("#woocommerce-facebook-settings-sync-products").click(function(e){e.preventDefault(),sync_confirm()})});
1
+ "use strict";var fb_sync_no_response_count=0,fb_show_advanced_options=!1;function openPopup(){var e,o=screen.height/2-404,n=screen.width/2-576.5;window.originParam=window.location.protocol+"//"+window.location.host,window.facebookAdsToolboxConfig.popupOrigin.includes("staticxx")&&(window.facebookAdsToolboxConfig.popupOrigin="https://www.facebook.com/"),window.facebookAdsToolboxConfig.popupOrigin=prepend_protocol(window.facebookAdsToolboxConfig.popupOrigin),e=window.facebookAdsToolboxConfig.popupOrigin;var t=window.open(e+"/login.php?display=popup&next="+encodeURIComponent(e+"/ads/dia?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=1153","height=808","top="+o,"left="+n].join(","));return function(e,o){t.postMessage({type:e,params:o},window.facebookAdsToolboxConfig.popupOrigin)}}function prepend_protocol(e){return 0===e.indexOf("//www.")&&(e="https:"+e),e}function get_pixel_id_box(){return document.querySelector("#woocommerce_facebookcommerce_facebook_pixel_id")}function get_pixel_use_pii_id_box(){return document.querySelector("#woocommerce_facebookcommerce_enable_advanced_matching")}function get_page_id_box(){return document.querySelector("#woocommerce_facebookcommerce_facebook_page_id")}function ajax(e){var o=1<arguments.length&&void 0!==arguments[1]?arguments[1]:null,n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null,t=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null,s=Object.assign({},{action:e},o);jQuery.post(ajaxurl,s,function(e){n&&n(e)}).fail(function(e){t&&t(e)})}var settings={facebook_for_woocommerce:1},pixel_settings={facebook_for_woocommerce:1};function facebookConfig(){window.sendToFacebook=openPopup(),window.diaConfig={clientSetup:window.facebookAdsToolboxConfig}}function fb_flush(){return console.log("Removing all FBIDs from all products!"),ajax("ajax_reset_all_fb_products",{_ajax_nonce:wc_facebook_settings_jsx.nonce},null,function(){console.log("Failed to reset all FB products")})}function sync_confirm(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null,o="";switch(e){case"fb_force_resync":o=facebook_for_woocommerce_settings_sync.i18n.confirm_resync;break;case"fb_test_product_sync":o=facebook_for_woocommerce_settings_sync.i18n.confirm_sync_test;break;default:o=facebook_for_woocommerce_settings_sync.i18n.confirm_sync}confirm(o)&&(sync_all_products(window.facebookAdsToolboxConfig.feed.hasClientSideFeedUpload,"fb_test_product_sync"==e),window.fb_sync_start_time=(new Date).getTime())}function sync_all_products(){var n=0<arguments.length&&void 0!==arguments[0]&&arguments[0],e=1<arguments.length&&void 0!==arguments[1]&&arguments[1];window.fb_connected=!0,sync_in_progress();var o={};o=n?(window.facebookAdsToolboxConfig.feed.hasClientSideFeedUpload=!0,window.feed_upload=!0,ping_feed_status_queue(),e?{action:"ajax_test_sync_products_using_feed"}:{action:"ajax_sync_all_fb_products_using_feed",_ajax_nonce:wc_facebook_settings_jsx.nonce}):(check_background_processor_status(),{action:"ajax_sync_all_fb_products",_ajax_nonce:wc_facebook_settings_jsx.nonce}),jQuery.post(ajaxurl,o).then(function(e){if(!e&&n||e&&!1===e.success){clearInterval(window.fb_pings),clearInterval(window.fb_feed_pings),jQuery("#woocommerce-facebook-settings-manage-connection, #woocommerce-facebook-settings-sync-products").css("pointer-events","auto");var o=void 0;o=e&&e.data&&e.data.error?e.data.error:facebook_for_woocommerce_settings_sync.i18n.general_error,$("#sync_progress").show().html('<span style="color: #DC3232">'+o+"</span>")}})}function delete_all_settings(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null,o=1<arguments.length&&void 0!==arguments[1]?arguments[1]:null;return get_pixel_id_box()&&(get_pixel_id_box().value=""),get_pixel_use_pii_id_box()&&(get_pixel_use_pii_id_box().checked=!1),get_page_id_box()&&(get_page_id_box().value=""),jQuery("#woocommerce_facebookcommerce_enable_messenger").prop("checked",!1).trigger("change"),jQuery(".messenger-field").each(function(){void 0!==$(this).data("default")&&$(this).val($(this).data("default")).trigger("change")}),window.facebookAdsToolboxConfig.pixel.pixelId="",window.facebookAdsToolboxConfig.diaSettingId="",window.fb_connected=!1,not_connected(),console.log("Deleting all settings and removing all FBIDs!"),ajax("ajax_delete_fb_settings",{_ajax_nonce:wc_facebook_settings_jsx.nonce},e,o)}function save_settings(){var o=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null,n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:null,e=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;(e=e||settings)._ajax_nonce=wc_facebook_settings_jsx.nonce,ajax("ajax_save_fb_settings",e,function(e){o&&o(e)},function(e){n&&n(e)})}function save_settings_for_plugin(o,n){save_settings(function(e){e&&e.includes("settings_saved")?(console.log(e),o(e)):(console.log("Fail response on save_settings_and_sync"),n(e))},function(e){console.log("Ajax error while saving settings:"+JSON.stringify(e)),n(e)})}function save_settings_and_sync(o){"api_key"in settings&&save_settings(function(e){e&&e.includes("settings_saved")?(console.log(e),window.sendToFacebook("ack set pixel",o.params),window.sendToFacebook("ack set page access token",o.params),window.sendToFacebook("ack set merchant settings",o.params),sync_all_products(!0)):(window.sendToFacebook("fail save_settings",e),console.log("Fail response on save_settings_and_sync"))},function(e){console.log("Ajax error while saving settings:"+JSON.stringify(e)),window.sendToFacebook("fail save_settings_ajax",JSON.stringify(e))})}function sync_in_progress(){jQuery("#woocommerce-facebook-settings-manage-connection, #woocommerce-facebook-settings-sync-products").css("pointer-events","none"),jQuery("#sync_progress").show().html(facebook_for_woocommerce_settings_sync.i18n.sync_in_progress)}function sync_not_in_progress(){jQuery("#woocommerce-facebook-settings-manage-connection, #woocommerce-facebook-settings-sync-products").css("pointer-events","auto"),jQuery("#sync_progress").empty().hide()}function not_connected(){jQuery("#fbsetup").show(),jQuery("#integration-settings").hide(),jQuery(".woocommerce-save-button").hide()}function addAnEventListener(e,o,n){"addEventListener"in e?e.addEventListener(o,n,!1):"attachEvent"in e&&e.attachEvent("on"+o,n)}function setMerchantSettings(e){if(!e.params.setting_id)return console.error("Facebook Extension Error: got no setting_id",e.params),void window.sendToFacebook("fail set merchant settings",e.params);settings.external_merchant_settings_id=e.params.setting_id,window.facebookAdsToolboxConfig.diaSettingId=e.params.setting_id}function setCatalog(e){if(!e.params.catalog_id)return console.error("Facebook Extension Error: got no catalog_id",e.params),void window.sendToFacebook("fail set catalog",e.params);settings.product_catalog_id=e.params.catalog_id,window.sendToFacebook("ack set catalog",e.params)}function setPixel(o){if(!o.params.pixel_id)return console.error("Facebook Ads Extension Error: got no pixel_id",o.params),void window.sendToFacebook("fail set pixel",o.params);get_pixel_id_box()&&(get_pixel_id_box().value=o.params.pixel_id),settings.pixel_id=o.params.pixel_id,pixel_settings.pixel_id=settings.pixel_id,void 0!==o.params.pixel_use_pii&&(get_pixel_use_pii_id_box()&&(get_pixel_use_pii_id_box().checked=!!o.params.pixel_use_pii),settings.pixel_use_pii=o.params.pixel_use_pii,pixel_settings.pixel_use_pii=settings.pixel_use_pii),save_settings(function(e){e&&e.includes("settings_saved")&&window.sendToFacebook("ack set pixel",o.params)},function(e){console.log(e),window.sendToFacebook("fail set pixel",e)},pixel_settings)}function genFeed(e){}function setAccessTokenAndPageId(e){if(!e.params.page_token)return console.error("Facebook Ads Extension Error: got no page_token",e.params),void window.sendToFacebook("fail set page access token",e.params);get_page_id_box()&&(get_page_id_box().value=e.params.page_id),settings.api_key=e.params.page_token,settings.page_id=e.params.page_id,window.facebookAdsToolboxConfig.tokenExpired=!1,document.querySelector("#connection-message-invalid")&&(document.querySelector("#connection-message-invalid").style.display="none"),document.querySelector("#connection-message-refresh")&&(document.querySelector("#connection-message-refresh").style.display="block")}function setMsgerChatSetup(e){if(e.hasOwnProperty("is_messenger_chat_plugin_enabled")&&(settings.is_messenger_chat_plugin_enabled=e.is_messenger_chat_plugin_enabled,jQuery("#woocommerce_facebookcommerce_enable_messenger").prop("checked",e.is_messenger_chat_plugin_enabled).trigger("change")),e.hasOwnProperty("facebook_jssdk_version")&&(settings.facebook_jssdk_version=e.facebook_jssdk_version),e.hasOwnProperty("page_id")&&(settings.fb_page_id=e.page_id),e.hasOwnProperty("customization")){var o=e.customization;o.hasOwnProperty("greetingTextCode")&&(settings.msger_chat_customization_greeting_text_code=o.greetingTextCode,jQuery("#woocommerce_facebookcommerce_messenger_greeting").val(o.greetingTextCode).trigger("change")),o.hasOwnProperty("locale")&&(settings.msger_chat_customization_locale=o.locale,jQuery("#woocommerce_facebookcommerce_messenger_locale").val(o.locale).trigger("change")),o.hasOwnProperty("themeColorCode")&&(settings.msger_chat_customization_theme_color_code=o.themeColorCode,jQuery("#woocommerce_facebookcommerce_messenger_color_hex").val(o.themeColorCode).trigger("change"))}}function iFrameListener(o){var e=o.origin||o.originalEvent.origin;switch(e!=window.facebookAdsToolboxConfig.popupOrigin&&urlFromSameDomain(e,window.facebookAdsToolboxConfig.popupOrigin)&&(window.facebookAdsToolboxConfig.popupOrigin=e),o.data.type){case"reset":delete_all_settings(function(e){e&&o.data.params?"Settings Deleted"===e?window.sendToFacebook("ack reset",o.data.params):(console.log(e),alert(e)):console.log("Got no response from delete_all_settings")},function(e){console.error(e)});break;case"get dia settings":window.sendToFacebook("dia settings",window.diaConfig);break;case"set merchant settings":setMerchantSettings(o.data);break;case"set catalog":setCatalog(o.data);break;case"set pixel":setPixel(o.data);break;case"gen feed":genFeed();break;case"set page access token":setAccessTokenAndPageId(o.data),save_settings_and_sync(o.data),jQuery("#fbsetup").hide(),jQuery("#integration-settings").show(),jQuery(".woocommerce-save-button").show();break;case"set msger chat":setMsgerChatSetup(o.data.params),save_settings_for_plugin(function(e){window.sendToFacebook("ack msger chat",o.data)},function(e){window.sendToFacebook("fail ack msger chat",o.data)})}}function urlFromSameDomain(e,o){if(!e.startsWith("http")||!o.startsWith("http"))return!1;var n=parseURL(e),t=parseURL(o),s=n.host.replace(/^\w+\./,"www."),i=t.host.replace(/^\w+\./,"www.");return n.protocol===t.protocol&&s===i}function parseURL(e){var o=document.createElement("a");return o.href=e,o}function check_background_processor_status(){window.facebookAdsToolboxConfig.feed.hasClientSideFeedUpload||(clearInterval(window.fb_pings),window.fb_pings=setInterval(function(){console.log("Pinging queue..."),check_queues()},1e4))}function ping_feed_status_queue(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:0;clearInterval(window.fb_feed_pings),window.fb_feed_pings=setInterval(function(){console.log("Pinging feed uploading queue..."),check_feed_upload_queue(e)},3e4*(1<<e))}function product_sync_complete(e){sync_not_in_progress(),e.empty().hide(),clearInterval(window.fb_pings)}function check_queues(){ajax("ajax_fb_background_check_queue",{request_time:(new Date).getTime(),_ajax_nonce:wc_facebook_settings_jsx.nonce},function(e){if(window.feed_upload)clearInterval(window.fb_pings);else{var o=jQuery("#sync_progress"),n=parse_response_check_connection(e);if(n){if(fb_sync_no_response_count=0,n){n.background||(console.log("No background sync found, disabling pings"),clearInterval(window.fb_pings));var t=!!n.processing,s=n.remaining;if(t){var i="";i=1===s?facebook_for_woocommerce_settings_sync.i18n.sync_remaining_items_singular:facebook_for_woocommerce_settings_sync.i18n.sync_remaining_items_plural,o.show().html(i.replace("{count}",s)),0===s&&product_sync_complete(o)}else{if(window.fb_sync_start_time&&n.request_time){var c=new Date(parseInt(n.request_time));if(window.fb_sync_start_time>c)return void console.log("OLD PING")}0===s&&product_sync_complete(o)}}}else 5<fb_sync_no_response_count++&&clearInterval(window.fb_pings)}})}function parse_response_check_connection(e){if(e){console.log(e);var o=e.substring(e.indexOf("{"));return(o=JSON.parse(o)).connected||window.fb_connected?o:(not_connected(),null)}return null}function check_feed_upload_queue(t){ajax("ajax_check_feed_upload_status",{_ajax_nonce:wc_facebook_settings_jsx.nonce},function(e){var o=jQuery("#sync_progress"),n=parse_response_check_connection(e);if(clearInterval(window.fb_feed_pings),n)switch(n.status){case"complete":window.feed_upload=!1,window.is_test?display_test_result():product_sync_complete(o);break;case"in progress":o.show().html(facebook_for_woocommerce_settings_sync.i18n.sync_in_progress),ping_feed_status_queue(t+1);break;default:jQuery("#woocommerce-facebook-settings-manage-connection, #woocommerce-facebook-settings-sync-products").css("pointer-events","auto"),$("#sync_progress").show().html('<span style="color: #DC3232">'+facebook_for_woocommerce_settings_sync.i18n.feed_upload_error+"</span>"),window.feed_upload=!1,window.is_test&&display_test_result()}})}function display_test_result(){ajax("ajax_display_test_result",{_ajax_nonce:wc_facebook_settings_jsx.nonce},function(e){var o=jQuery("#sync_progress"),n=document.querySelector("#sync_complete"),t=parse_response_check_connection(e);if(t)switch(t.pass){case"true":sync_not_in_progress(),n&&(n.style.display="",n.innerHTML=facebook_for_woocommerce_settings_sync.i18n.integration_test_sucessful),o.empty().hide(),window.is_test=!1;break;case"in progress":o.show().html(facebook_for_woocommerce_settings_sync.i18n.integration_test_in_progress),ping_feed_status_queue();break;default:window.debug_info=t.debug_info+"<br/>"+t.stack_trace,n&&(n.style.display="",n.innerHTML=facebook_for_woocommerce_settings_sync.i18n.integration_test_failed),o.empty().hide(),document.querySelector("#debug_info")&&(document.querySelector("#debug_info").style.display=""),window.is_test=!1}})}function show_debug_info(){var e=document.querySelector("#stack_trace");e&&(e.innerHTML=window.debug_info),document.querySelector("#debug_info")&&(document.querySelector("#debug_info").style.display="none"),window.debug_info=""}function fbe_init_nux_messages(){var r=window.jQuery;r(function(){r.each(r(".nux-message"),function(e,o){var n=r(o),t=n.data("target"),s=r("#"+t),i=s.position(),c=s.height()/2,a=s.outerWidth();n.css({top:Math.ceil(i.top+c)+"px",left:Math.ceil(i.left+a)+"px",display:"block"}),r(".nux-message-close-btn",n).click(function(){r(o).hide()})})})}function saveAutoSyncSchedule(){var e=document.getElementsByClassName("autosyncCheck")[0].checked,o=document.getElementsByClassName("autosyncTime")[0],n=(document.getElementsByClassName("autosyncSaveButton")[0],document.getElementsByClassName("autosyncSavedNotice")[0]);e?(o.removeAttribute("disabled"),n.style.transition="",n.style.opacity=1,setTimeout(function(){n.style.opacity=0,n.style.transition="opacity 5s"},3e3)):o.setAttribute("disabled",!0),ajax("ajax_schedule_force_resync",{enabled:e?1:0,time:o.value,_ajax_nonce:wc_facebook_settings_jsx.nonce})}function syncShortDescription(){var e=document.getElementsByClassName("syncShortDescription")[0].checked;ajax("ajax_update_fb_option",{option:"fb_sync_short_description",option_value:e?1:0,_ajax_nonce:wc_facebook_settings_jsx.nonce},null,function(){document.getElementsByClassName("syncShortDescription")[0].checked=!e,console.log("Failed to sync Short Description")})}window.location.href.includes("fb_force_resync")?window.onload=function(){sync_confirm("fb_force_resync")}:window.location.href.includes("fb_test_product_sync")&&(window.is_test=!0,window.onload=function(){sync_confirm("fb_test_product_sync")}),addAnEventListener(window,"message",iFrameListener),jQuery(document).ready(function(e){check_background_processor_status(),e("#woocommerce-facebook-settings-sync-products").click(function(e){e.preventDefault(),sync_confirm()})});
changelog.txt CHANGED
@@ -1,8 +1,24 @@
1
*** Facebook for WooCommerce Changelog ***
2
3
2020.03.10 - version 1.10.1
4
* Fix - Prevent Fatal error during the upgrade routine introduced in version 1.10.0
5
* Fix - Only load the admin settings JavaScript on the Facebook settings page to prevent conflicts with other scripts
6
7
2020.03.03 - version 1.10.0
8
* Feature - Exclude specific products, variations, product categories, and product tags from syncing to Facebook
@@ -10,8 +26,8 @@
10
* Feature - Revamped settings screen with on-site control over pixel, product sync, and Messenger behavior
11
* Tweak - Use Action Scheduler for the daily forced re-sync, if enabled
12
* Fix - Improve pixel tracking accuracy for add-to-cart events
13
- * Misc. - Add the SkyVerge plugin framework as the plugin base
14
- * Misc. - Require WooCommerce 3.5 and above
15
16
2019-06-27 - Version 1.9.15
17
* CSRF handling for Ajax calls like ajax_woo_infobanner_post_click, ajax_woo_infobanner_post_xout, ajax_fb_toggle_visibility
1
*** Facebook for WooCommerce Changelog ***
2
3
+ 2020.03.17 - version 1.10.2
4
+ * Tweak - Add a setting to easily enable debug logging
5
+ * Tweak - Allow third party plugins and themes to track an add-to-cart event on added_to_cart JS event
6
+ * Tweak - When excluding a product term from syncing in the plugin settings page, offer an option to hide excluded synced products from Facebook
7
+ * Tweak - When excluding product terms from syncing in the plugin settings page, and settings are saved, exclude corresponding products from sync
8
+ * Tweak - Improve error messages shown when a problem occurs during products sync
9
+ * Tweak - Log Graph API communication if logging is enabled
10
+ * Fix - When excluding a product term from syncing in the plugin settings page, ensure a modal opens to warn about possible conflicts with already synced products
11
+ * Fix - Messenger settings fields will correctly reflect the values selected during initial setup
12
+ * Fix - Fix a bug that caused newly added gallery images not to be synced immediately after they were added
13
+ * Fix - Fix a bug that prevented gallery images from being removed from products on Facebook
14
+ * Fix - Fix AddToCart Pixel event tracking when adding products from archive with AJAX and redirect to cart enabled
15
+ * Fix - Fix undefined index and undefined property notices
16
+ * Dev - Make Pixel script attributes and event parameters filterable
17
+
18
2020.03.10 - version 1.10.1
19
* Fix - Prevent Fatal error during the upgrade routine introduced in version 1.10.0
20
* Fix - Only load the admin settings JavaScript on the Facebook settings page to prevent conflicts with other scripts
21
+ * Misc - Add support for WooCommerce 4.0
22
23
2020.03.03 - version 1.10.0
24
* Feature - Exclude specific products, variations, product categories, and product tags from syncing to Facebook
26
* Feature - Revamped settings screen with on-site control over pixel, product sync, and Messenger behavior
27
* Tweak - Use Action Scheduler for the daily forced re-sync, if enabled
28
* Fix - Improve pixel tracking accuracy for add-to-cart events
29
+ * Misc - Add the SkyVerge plugin framework as the plugin base
30
+ * Misc - Require WooCommerce 3.5 and above
31
32
2019-06-27 - Version 1.9.15
33
* CSRF handling for Ajax calls like ajax_woo_infobanner_post_click, ajax_woo_infobanner_post_xout, ajax_fb_toggle_visibility
class-wc-facebookcommerce.php CHANGED
@@ -19,7 +19,7 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
19
20
21
/** @var string the plugin version */
22
- const VERSION = '1.10.1';
23
24
/** @var string for backwards compatibility TODO: remove this in v2.0.0 {CW 2020-02-06} */
25
const PLUGIN_VERSION = self::VERSION;
19
20
21
/** @var string the plugin version */
22
+ const VERSION = '1.10.2';
23
24
/** @var string for backwards compatibility TODO: remove this in v2.0.0 {CW 2020-02-06} */
25
const PLUGIN_VERSION = self::VERSION;
facebook-commerce-events-tracker.php CHANGED
@@ -58,6 +58,7 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
58
// AddToCart while using redirect to cart page
59
if ( 'yes' === get_option( 'woocommerce_cart_redirect_after_add' ) ) {
60
add_filter( 'woocommerce_add_to_cart_redirect', [ $this, 'set_last_product_added_to_cart_upon_redirect' ], 10, 2 );
61
add_action( 'woocommerce_after_cart', [ $this, 'inject_add_to_cart_redirect_event' ], 10, 2 );
62
}
63
@@ -281,7 +282,7 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
281
*
282
* @internal
283
*
284
- * @since x.y.z
285
*/
286
public function add_filter_for_add_to_cart_fragments() {
287
@@ -296,7 +297,7 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
296
*
297
* @internal
298
*
299
- * @since x.y.z
300
*
301
* @param array $fragments add to cart fragments
302
* @return array
@@ -320,15 +321,65 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
320
}
321
322
323
/**
324
* Sends a JSON response with the JavaScript code to track an AddToCart event.
325
*
326
* @internal
327
- * @deprecated since x.y.z
328
*/
329
public function inject_ajax_add_to_cart_event() {
330
331
- wc_deprecated_function( __METHOD__, 'x.y.z' );
332
}
333
334
@@ -337,7 +388,7 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
337
*
338
* @internal
339
*
340
- * @since x.y.z
341
*
342
* @param string $redirect URL redirecting to (usually cart)
343
* @param \WC_Product $product the product just added to the cart
@@ -353,6 +404,25 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
353
}
354
355
356
/**
357
* Triggers an AddToCart event when redirecting to the cart page.
358
*
@@ -494,7 +564,7 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
494
/**
495
* Gets the cart content items count.
496
*
497
- * @since x.y.z
498
*
499
* @return int
500
*/
@@ -507,7 +577,7 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
507
/**
508
* Gets all content IDs from cart.
509
*
510
- * @since x.y.z
511
*
512
* @return string JSON data
513
*/
@@ -533,7 +603,7 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
533
/**
534
* Gets the cart content data.
535
*
536
- * @since x.y.z
537
*
538
* @return string JSON data
539
*/
58
// AddToCart while using redirect to cart page
59
if ( 'yes' === get_option( 'woocommerce_cart_redirect_after_add' ) ) {
60
add_filter( 'woocommerce_add_to_cart_redirect', [ $this, 'set_last_product_added_to_cart_upon_redirect' ], 10, 2 );
61
+ add_action( 'woocommerce_ajax_added_to_cart', [ $this, 'set_last_product_added_to_cart_upon_ajax_redirect' ] );
62
add_action( 'woocommerce_after_cart', [ $this, 'inject_add_to_cart_redirect_event' ], 10, 2 );
63
}
64
282
*
283
* @internal
284
*
285
+ * @since 1.10.2
286
*/
287
public function add_filter_for_add_to_cart_fragments() {
288
297
*
298
* @internal
299
*
300
+ * @since 1.10.2
301
*
302
* @param array $fragments add to cart fragments
303
* @return array
321
}
322
323
324
+ /**
325
+ * Setups a filter to add an add to cart fragment to trigger an AddToCart event on added_to_cart JS event.
326
+ *
327
+ * This method is used by code snippets and should not be removed.
328
+ *
329
+ * @see \WC_Facebookcommerce_EventsTracker::add_conditional_add_to_cart_event_fragment
330
+ *
331
+ * @internal
332
+ *
333
+ * @since 1.10.2
334
+ */
335
+ public function add_filter_for_conditional_add_to_cart_fragment() {
336
+
337
+ if ( 'no' === get_option( 'woocommerce_cart_redirect_after_add' ) ) {
338
+ add_filter( 'woocommerce_add_to_cart_fragments', [ $this, 'add_conditional_add_to_cart_event_fragment' ] );
339
+ }
340
+ }
341
+
342
+
343
+ /**
344
+ * Adds an add to cart fragment to trigger an AddToCart event on added_to_cart JS event.
345
+ *
346
+ * @internal
347
+ *
348
+ * @since 1.10.2
349
+ *
350
+ * @param array $fragments add to cart fragments
351
+ * @return array
352
+ */
353
+ public function add_conditional_add_to_cart_event_fragment( $fragments ) {
354
+
355
+ if ( self::$isEnabled ) {
356
+
357
+ $params = [
358
+ 'content_ids' => $this->get_cart_content_ids(),
359
+ 'content_type' => 'product',
360
+ 'contents' => $this->get_cart_contents(),
361
+ 'value' => $this->get_cart_total(),
362
+ 'currency' => get_woocommerce_currency(),
363
+ ];
364
+
365
+ $script = $this->pixel->get_conditional_one_time_event_script( 'AddToCart', $params, 'added_to_cart' );
366
+
367
+ $fragments['div.wc-facebook-pixel-event-placeholder'] = '<div class="wc-facebook-pixel-event-placeholder">' . $script . '</div>';
368
+ }
369
+
370
+ return $fragments;
371
+ }
372
+
373
+
374
/**
375
* Sends a JSON response with the JavaScript code to track an AddToCart event.
376
*
377
* @internal
378
+ * @deprecated since 1.10.2
379
*/
380
public function inject_ajax_add_to_cart_event() {
381
382
+ wc_deprecated_function( __METHOD__, '1.10.2' );
383
}
384
385
388
*
389
* @internal
390
*
391
+ * @since 1.10.2
392
*
393
* @param string $redirect URL redirecting to (usually cart)
394
* @param \WC_Product $product the product just added to the cart
404
}
405
406
407
+ /**
408
+ * Sets last product added to cart to session when adding a product to cart from an archive page and both AJAX adding and redirection to cart are enabled.
409
+ *
410
+ * @internal
411
+ *
412
+ * @since 1.10.2
413
+ *
414
+ * @param int $product_id the ID of the product just added to the cart
415
+ */
416
+ public function set_last_product_added_to_cart_upon_ajax_redirect( $product_id ) {
417
+
418
+ $product = wc_get_product( $product_id );
419
+
420
+ if ( $product instanceof \WC_Product ) {
421
+ WC()->session->set( 'facebook_for_woocommerce_last_product_added_to_cart', $product->get_id() );
422
+ }
423
+ }
424
+
425
+
426
/**
427
* Triggers an AddToCart event when redirecting to the cart page.
428
*
564
/**
565
* Gets the cart content items count.
566
*
567
+ * @since 1.10.2
568
*
569
* @return int
570
*/
577
/**
578
* Gets all content IDs from cart.
579
*
580
+ * @since 1.10.2
581
*
582
* @return string JSON data
583
*/
603
/**
604
* Gets the cart content data.
605
*
606
+ * @since 1.10.2
607
*
608
* @return string JSON data
609
*/
facebook-commerce-pixel-event.php CHANGED
@@ -12,28 +12,27 @@ if ( ! class_exists( 'WC_Facebookcommerce_Pixel' ) ) :
12
13
14
class WC_Facebookcommerce_Pixel {
15
const SETTINGS_KEY = 'facebook_config';
16
const PIXEL_ID_KEY = 'pixel_id';
17
const USE_PII_KEY = 'use_pii';
18
19
const PIXEL_RENDER = 'pixel_render';
20
const NO_SCRIPT_RENDER = 'no_script_render';
21
22
private $user_info;
23
private $last_event;
24
- static $render_cache = array();
25
-
26
- static $default_pixel_basecode = "
27
- <script type='text/javascript'>
28
- !function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
29
- n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
30
- n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
31
- t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
32
- document,'script','https://connect.facebook.net/en_US/fbevents.js');
33
- </script>
34
- ";
35
36
public function __construct( $user_info = array() ) {
37
$this->user_info = $user_info;
38
$this->last_event = '';
39
}
@@ -68,53 +67,122 @@ document,'script','https://connect.facebook.net/en_US/fbevents.js');
68
}
69
}
70
71
/**
72
- * Returns FB pixel code script part
73
*/
74
public function pixel_base_code() {
75
$pixel_id = self::get_pixel_id();
76
- if (
77
- (
78
- isset( self::$render_cache[ self::PIXEL_RENDER ] ) &&
79
- self::$render_cache[ self::PIXEL_RENDER ] === true
80
- ) ||
81
- ! isset( $pixel_id ) ||
82
- $pixel_id === 0
83
- ) {
84
- return;
85
}
86
87
self::$render_cache[ self::PIXEL_RENDER ] = true;
88
- $params = self::add_version_info();
89
90
- return sprintf(
91
- "
92
- <!-- %s Facebook Integration Begin -->
93
- %s
94
- <script>
95
- %s
96
- fbq( 'track', 'PageView', %s );
97
-
98
- document.addEventListener( 'DOMContentLoaded', function() {
99
- jQuery && jQuery( function( $ ) {
100
-
101
- // insert placeholder for events injected when a product is added to the cart through Ajax
102
- $( document.body ).append( '<div class=\"wc-facebook-pixel-event-placeholder\"></div>' );
103
- } );
104
- }, false );
105
-
106
- </script>
107
- <!-- DO NOT MODIFY -->
108
- <!-- %s Facebook Integration end -->
109
- ",
110
- esc_html( WC_Facebookcommerce_Utils::getIntegrationName() ),
111
- self::get_basecode(),
112
- $this->pixel_init_code(),
113
- json_encode( $params, JSON_PRETTY_PRINT | JSON_FORCE_OBJECT ),
114
- esc_html( WC_Facebookcommerce_Utils::getIntegrationName() )
115
- );
116
}
117
118
/**
119
* Prevent double-fires by checking the last event
120
*/
@@ -130,11 +198,12 @@ document.addEventListener( 'DOMContentLoaded', function() {
130
*
131
* Use {@see \WC_Facebookcommerce_Pixel::inject_event()} to print or enqueue the code.
132
*
133
- * @since x.y.z
134
*
135
* @param string $event_name the name of the event to track
136
* @param array $params custom event parameters
137
* @param string $method name of the pixel's fbq() function to call
138
*/
139
public function get_event_code( $event_name, $params, $method = 'track' ) {
140
@@ -149,23 +218,26 @@ document.addEventListener( 'DOMContentLoaded', function() {
149
*
150
* @see \WC_Facebookcommerce_Pixel::get_event_code()
151
*
152
- * @since x.y.z
153
*
154
* @param string $event_name the name of the event to track
155
* @param array $params custom event parameters
156
* @param string $method name of the pixel's fbq() function to call
157
*/
158
public function get_event_script( $event_name, $params, $method = 'track' ) {
159
160
- $output = '
161
- <!-- Facebook Pixel Event Code -->
162
- <script>
163
- %s
164
- </script>
165
- <!-- End Facebook Pixel Event Code -->
166
- ';
167
168
- return sprintf( $output, $this->get_event_code( $event_name, $params, $method ) );
169
}
170
171
@@ -173,7 +245,6 @@ document.addEventListener( 'DOMContentLoaded', function() {
173
* Prints or enqueues the JavaScript code to track an event.
174
*
175
* Preferred method to inject events in a page.
176
- *
177
* @see \WC_Facebookcommerce_Pixel::build_event()
178
*
179
* @param string $event_name the name of the event to track
@@ -182,29 +253,32 @@ document.addEventListener( 'DOMContentLoaded', function() {
182
*/
183
public function inject_event( $event_name, $params, $method = 'track' ) {
184
185
- if ( WC_Facebookcommerce_Utils::isWoocommerceIntegration() ) {
186
187
- WC_Facebookcommerce_Utils::wc_enqueue_js( $this->get_event_code( $event_name, $params, $method ) );
188
189
} else {
190
191
// phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
192
- printf( $this->get_event_script( $event_name, $params, $method ) );
193
}
194
}
195
196
197
/**
198
- * Prints the JavaScript code to track a conditional event.
199
*
200
- * The tracking code will be executed when the given JavaScript event is triggered.
201
*
202
- * @param string $event_name
203
* @param array $params custom event parameters
204
* @param string $listener name of the JavaScript event to listen for
205
* @param string $jsonified_pii JavaScript code representing an object of data for Advanced Matching
206
*/
207
- public function inject_conditional_event( $event_name, $params, $listener, $jsonified_pii = '' ) {
208
209
$code = self::build_event( $event_name, $params, 'track' );
210
$this->last_event = $event_name;
@@ -213,73 +287,157 @@ document.addEventListener( 'DOMContentLoaded', function() {
213
// Prepends fbq(...) with pii information to the injected code.
214
if ( $jsonified_pii && get_option( self::SETTINGS_KEY )[ self::USE_PII_KEY ] ) {
215
$this->user_info = '%s';
216
- $code =
217
- sprintf( $this->pixel_init_code(), '" || ' . $jsonified_pii . ' || "' ) . $code;
218
}
219
220
- $output = "
221
- <!-- Facebook Pixel Event Code -->
222
- <script>
223
- document.addEventListener('%s', function (event) {
224
- %s
225
- }, false );
226
- </script>
227
- <!-- End Facebook Pixel Event Code -->
228
- ";
229
230
// phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
231
- printf( $output, esc_js( $listener ), $code );
232
}
233
234
235
/**
236
- * Returns FB pixel code noscript part to avoid W3 validation error
237
*/
238
- public function pixel_base_code_noscript() {
239
- $pixel_id = self::get_pixel_id();
240
- if (
241
- (
242
- isset( self::$render_cache[ self::NO_SCRIPT_RENDER ] ) &&
243
- self::$render_cache[ self::NO_SCRIPT_RENDER ] === true
244
- ) ||
245
- ! isset( $pixel_id ) ||
246
- $pixel_id === 0
247
- ) {
248
- return;
249
- }
250
251
- self::$render_cache[ self::NO_SCRIPT_RENDER ] = true;
252
253
- return sprintf(
254
- '
255
- <!-- Facebook Pixel Code -->
256
- <noscript>
257
- <img height="1" width="1" style="display:none" alt="fbpx"
258
- src="https://www.facebook.com/tr?id=%s&ev=PageView&noscript=1"/>
259
- </noscript>
260
- <!-- DO NOT MODIFY -->
261
- <!-- End Facebook Pixel Code -->
262
- ',
263
- esc_attr( $pixel_id )
264
- );
265
}
266
267
/**
268
- * You probably should use WC_Facebookcommerce_Pixel::inject_event() but
269
- * this method is available if you need to modify the JS code somehow
270
*/
271
public static function build_event( $event_name, $params, $method = 'track' ) {
272
- $params = self::add_version_info( $params );
273
return sprintf(
274
"/* %s Facebook Integration Event Tracking */\n" .
275
"fbq('%s', '%s', %s);",
276
WC_Facebookcommerce_Utils::getIntegrationName(),
277
esc_js( $method ),
278
esc_js( $event_name ),
279
- json_encode( $params, JSON_PRETTY_PRINT | JSON_FORCE_OBJECT )
280
);
281
}
282
283
public static function get_pixel_id() {
284
$fb_options = self::get_options();
285
if ( ! $fb_options ) {
@@ -322,10 +480,6 @@ src="https://www.facebook.com/tr?id=%s&ev=PageView&noscript=1"/>
322
update_option( self::SETTINGS_KEY, $fb_options );
323
}
324
325
- public static function get_basecode() {
326
- return self::$default_pixel_basecode;
327
- }
328
-
329
private static function get_version_info() {
330
global $wp_version;
331
@@ -354,44 +508,22 @@ src="https://www.facebook.com/tr?id=%s&ev=PageView&noscript=1"/>
354
);
355
}
356
357
- /**
358
- * Returns an array with version_info for pixel fires. Parameters provided by
359
- * users should not be overwritten by this function
360
- */
361
- private static function add_version_info( $params = array() ) {
362
- // if any parameter is passed in the pixel, do not overwrite it
363
- return array_replace( self::get_version_info(), $params );
364
- }
365
366
/**
367
- * Init code might contain additional information to help matching website
368
- * users with facebook users. Information is hashed in JS side using SHA256
369
- * before sending to Facebook.
370
*/
371
- private function pixel_init_code() {
372
- $version_info = self::get_version_info();
373
- $agent_string = sprintf(
374
- '%s-%s-%s',
375
- $version_info['source'],
376
- $version_info['version'],
377
- $version_info['pluginVersion']
378
- );
379
380
- $params = array(
381
- 'agent' => $agent_string,
382
- );
383
384
- return apply_filters(
385
- 'facebook_woocommerce_pixel_init',
386
- sprintf(
387
- "fbq('init', '%s', %s, %s);\n",
388
- esc_js( self::get_pixel_id() ),
389
- json_encode( $this->user_info, JSON_PRETTY_PRINT | JSON_FORCE_OBJECT ),
390
- json_encode( $params, JSON_PRETTY_PRINT | JSON_FORCE_OBJECT )
391
- )
392
- );
393
}
394
395
}
396
397
endif;
12
13
14
class WC_Facebookcommerce_Pixel {
15
+
16
+
17
const SETTINGS_KEY = 'facebook_config';
18
const PIXEL_ID_KEY = 'pixel_id';
19
const USE_PII_KEY = 'use_pii';
20
21
+ /** @var string cache key for pixel script block output */
22
const PIXEL_RENDER = 'pixel_render';
23
+ /** @var string cache key for pixel noscript block output */
24
const NO_SCRIPT_RENDER = 'no_script_render';
25
26
+ /** @var array script render memoization helper */
27
+ public static $render_cache = [];
28
+
29
private $user_info;
30
+
31
private $last_event;
32
+
33
34
public function __construct( $user_info = array() ) {
35
+
36
$this->user_info = $user_info;
37
$this->last_event = '';
38
}
67
}
68
}
69
70
+
71
/**
72
+ * Gets Facebook Pixel init code.
73
+ *
74
+ * Init code might contain additional information to help matching website users with facebook users.
75
+ * Information is hashed in JS side using SHA256 before sending to Facebook.
76
+ *
77
+ * @return string
78
+ */
79
+ private function get_pixel_init_code() {
80
+
81
+ $version_info = self::get_version_info();
82
+ $agent_string = sprintf(
83
+ '%s-%s-%s',
84
+ $version_info['source'],
85
+ $version_info['version'],
86
+ $version_info['pluginVersion']
87
+ );
88
+
89
+ /**
90
+ * Filters Facebook Pixel init code.
91
+ *
92
+ * @param string $js_code
93
+ */
94
+ return apply_filters( 'facebook_woocommerce_pixel_init', sprintf(
95
+ "fbq('init', '%s', %s, %s);\n",
96
+ esc_js( self::get_pixel_id() ),
97
+ json_encode( $this->user_info, JSON_PRETTY_PRINT | JSON_FORCE_OBJECT ),
98
+ json_encode( [ 'agent' => $agent_string ], JSON_PRETTY_PRINT | JSON_FORCE_OBJECT )
99
+ ) );
100
+ }
101
+
102
+
103
+ /**
104
+ * Gets the Facebook Pixel code scripts.
105
+ *
106
+ * @return string HTML scripts
107
*/
108
public function pixel_base_code() {
109
+
110
$pixel_id = self::get_pixel_id();
111
+
112
+ // bail if no ID or already rendered
113
+ if ( empty( $pixel_id )|| ! empty( self::$render_cache[ self::PIXEL_RENDER ] ) ) {
114
+ return '';
115
}
116
117
self::$render_cache[ self::PIXEL_RENDER ] = true;
118
119
+ ob_start();
120
+
121
+ ?>
122
+ <script <?php echo self::get_script_attributes(); ?>>
123
+ !function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
124
+ n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
125
+ n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
126
+ t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
127
+ document,'script','https://connect.facebook.net/en_US/fbevents.js');
128
+ </script>
129
+ <!-- WooCommerce Facebook Integration Begin -->
130
+ <script <?php echo self::get_script_attributes(); ?>>
131
+
132
+ <?php echo $this->get_pixel_init_code(); ?>
133
+
134
+ fbq( 'track', 'PageView', <?php echo json_encode( self::build_params( [], 'PageView' ), JSON_PRETTY_PRINT | JSON_FORCE_OBJECT ) ?> );
135
+
136
+ document.addEventListener( 'DOMContentLoaded', function() {
137
+ jQuery && jQuery( function( $ ) {
138
+ // insert placeholder for events injected when a product is added to the cart through AJAX
139
+ $( document.body ).append( '<div class=\"wc-facebook-pixel-event-placeholder\"></div>' );
140
+ } );
141
+ }, false );
142
+
143
+ </script>
144
+ <!-- WooCommerce Facebook Integration End -->
145
+ <?php
146
+
147
+ return ob_get_clean();
148
+ }
149
+
150
+
151
+ /**
152
+ * Gets Facebook Pixel code noscript part to avoid W3 validation errors.
153
+ *
154
+ * @return string
155
+ */
156
+ public function pixel_base_code_noscript() {
157
+
158
+ $pixel_id = self::get_pixel_id();
159
+
160
+ if ( empty( $pixel_id ) || ! empty( self::$render_cache[ self::NO_SCRIPT_RENDER ] ) ) {
161
+ return '';
162
+ }
163
+
164
+ self::$render_cache[ self::NO_SCRIPT_RENDER ] = true;
165
+
166
+ ob_start();
167
+
168
+ ?>
169
+ <!-- Facebook Pixel Code -->
170
+ <noscript>
171
+ <img
172
+ height="1"
173
+ width="1"
174
+ style="display:none"
175
+ alt="fbpx"
176
+ src="https://www.facebook.com/tr?id=<?php echo esc_attr( $pixel_id ); ?>&ev=PageView&noscript=1"
177
+ />
178
+ </noscript>
179
+ <!-- End Facebook Pixel Code -->
180
+ <?php
181
+
182
+ return ob_get_clean();
183
}
184
185
+
186
/**
187
* Prevent double-fires by checking the last event
188
*/
198
*
199
* Use {@see \WC_Facebookcommerce_Pixel::inject_event()} to print or enqueue the code.
200
*
201
+ * @since 1.10.2
202
*
203
* @param string $event_name the name of the event to track
204
* @param array $params custom event parameters
205
* @param string $method name of the pixel's fbq() function to call
206
+ * @return string
207
*/
208
public function get_event_code( $event_name, $params, $method = 'track' ) {
209
218
*
219
* @see \WC_Facebookcommerce_Pixel::get_event_code()
220
*
221
+ * @since 1.10.2
222
*
223
* @param string $event_name the name of the event to track
224
* @param array $params custom event parameters
225
* @param string $method name of the pixel's fbq() function to call
226
+ * @return string
227
*/
228
public function get_event_script( $event_name, $params, $method = 'track' ) {
229
230
+ ob_start();
231
+
232
+ ?>
233
+ <!-- Facebook Pixel Event Code -->
234
+ <script <?php echo self::get_script_attributes(); ?>>
235
+ <?php echo $this->get_event_code( $event_name, $params, $method ); ?>
236
+ </script>
237
+ <!-- End Facebook Pixel Event Code -->
238
+ <?php
239
240
+ return ob_get_clean();
241
}
242
243
245
* Prints or enqueues the JavaScript code to track an event.
246
*
247
* Preferred method to inject events in a page.
248
* @see \WC_Facebookcommerce_Pixel::build_event()
249
*
250
* @param string $event_name the name of the event to track
253
*/
254
public function inject_event( $event_name, $params, $method = 'track' ) {
255
256
+ if ( \WC_Facebookcommerce_Utils::isWoocommerceIntegration() ) {
257
258
+ \WC_Facebookcommerce_Utils::wc_enqueue_js( $this->get_event_code( $event_name, self::build_params( $params, $event_name ), $method ) );
259
260
} else {
261
262
// phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
263
+ printf( $this->get_event_script( $event_name, self::build_params( $params, $event_name ), $method ) );
264
}
265
}
266
267
268
/**
269
+ * Gets the JavaScript code to track a conditional event wrapped in <script> tag.
270
*
271
+ * @see \WC_Facebookcommerce_Pixel::get_event_code()
272
*
273
+ * @since 1.10.2
274
+ *
275
+ * @param string $event_name the name of the event to track
276
* @param array $params custom event parameters
277
* @param string $listener name of the JavaScript event to listen for
278
* @param string $jsonified_pii JavaScript code representing an object of data for Advanced Matching
279
+ * @return string
280
*/
281
+ public function get_conditional_event_script( $event_name, $params, $listener, $jsonified_pii ) {
282
283
$code = self::build_event( $event_name, $params, 'track' );
284
$this->last_event = $event_name;
287
// Prepends fbq(...) with pii information to the injected code.
288
if ( $jsonified_pii && get_option( self::SETTINGS_KEY )[ self::USE_PII_KEY ] ) {
289
$this->user_info = '%s';
290
+ $code = sprintf( $this->get_pixel_init_code(), '" || ' . $jsonified_pii . ' || "' ) . $code;
291
}
292
293
+ ob_start();
294
+
295
+ ?>
296
+ <!-- Facebook Pixel Event Code -->
297
+ <script <?php echo self::get_script_attributes(); ?>>
298
+ document.addEventListener( '<?php echo esc_js( $listener ); ?>', function (event) {
299
+ <?php echo $code; ?>
300
+ }, false );
301
+ </script>
302
+ <!-- End Facebook Pixel Event Code -->
303
+ <?php
304
+
305
+ return ob_get_clean();
306
+ }
307
+
308
+
309
+ /**
310
+ * Prints the JavaScript code to track a conditional event.
311
+ *
312
+ * The tracking code will be executed when the given JavaScript event is triggered.
313
+ *
314
+ * @param string $event_name
315
+ * @param array $params custom event parameters
316
+ * @param string $listener name of the JavaScript event to listen for
317
+ * @param string $jsonified_pii JavaScript code representing an object of data for Advanced Matching
318
+ * @return string
319
+ */
320
+ public function inject_conditional_event( $event_name, $params, $listener, $jsonified_pii = '' ) {
321
322
// phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
323
+ return $this->get_conditional_event_script( $event_name, self::build_params( $params, $event_name ), $listener, $jsonified_pii );
324
}
325
326
327
/**
328
+ * Gets the JavaScript code to track a conditional event that is only triggered one time wrapped in <script> tag.
329
+ *
330
+ * @internal
331
+ *
332
+ * @since 1.10.2
333
+ *
334
+ * @param string $event_name the name of the event to track
335
+ * @param array $params custom event parameters
336
+ * @param string $listened_event name of the JavaScript event to listen for
337
+ * @return string
338
*/
339
+ public function get_conditional_one_time_event_script( $event_name, $params, $listened_event ) {
340
341
+ $code = $this->get_event_code( $event_name, $params );
342
343
+ ob_start();
344
+
345
+ ?>
346
+ <!-- Facebook Pixel Event Code -->
347
+ <script <?php echo self::get_script_attributes(); ?>>
348
+ function handle<?php echo $event_name; ?>Event() {
349
+ <?php echo $code; ?>
350
+ // some weird themes (hi, Basel) are running this script twice, so two listeners are added and we need to remove them after running one
351
+ jQuery( document.body ).off( '<?php echo esc_js( $listened_event ); ?>', handle<?php echo $event_name; ?>Event );
352
+ }
353
+
354
+ jQuery( document.body ).one( '<?php echo esc_js( $listened_event ); ?>', handle<?php echo $event_name; ?>Event );
355
+ </script>
356
+ <!-- End Facebook Pixel Event Code -->
357
+ <?php
358
+
359
+ return ob_get_clean();
360
}
361
362
+
363
/**
364
+ * Builds an event.
365
+ *
366
+ * @see \WC_Facebookcommerce_Pixel::inject_event() for the preferred method to inject an event.
367
+ *
368
+ * @param string $event_name event name
369
+ * @param array $params event params
370
+ * @param string $method optional, defaults to 'track'
371
+ * @return string
372
*/
373
public static function build_event( $event_name, $params, $method = 'track' ) {
374
+
375
return sprintf(
376
"/* %s Facebook Integration Event Tracking */\n" .
377
"fbq('%s', '%s', %s);",
378
WC_Facebookcommerce_Utils::getIntegrationName(),
379
esc_js( $method ),
380
esc_js( $event_name ),
381
+ json_encode( self::build_params( $params, $event_name ), JSON_PRETTY_PRINT | JSON_FORCE_OBJECT )
382
);
383
}
384
385
+
386
+ /**
387
+ * Gets an array with version_info for pixel fires.
388
+ *
389
+ * Parameters provided by users should not be overwritten by this function.
390
+ *
391
+ * @since 1.10.2
392
+ *
393
+ * @param array $params user defined parameters
394
+ * @param string $event the event name the params are for
395
+ * @return array
396
+ */
397
+ private static function build_params( $params = [], $event = '' ) {
398
+
399
+ $params = array_replace( self::get_version_info(), $params );
400
+
401
+ /**
402
+ * Filters the parameters for the pixel code.
403
+ *
404
+ * @since 1.10.2
405
+ *
406
+ * @param array $params user defined parameters
407
+ * @param string $event the event name
408
+ */
409
+ return (array) apply_filters( 'wc_facebook_pixel_params', $params, $event );
410
+ }
411
+
412
+
413
+ /**
414
+ * Gets script tag attributes.
415
+ *
416
+ * @since 1.10.2
417
+ *
418
+ * @return string
419
+ */
420
+ private static function get_script_attributes() {
421
+
422
+ $script_attributes = '';
423
+
424
+ /**
425
+ * Filters Facebook Pixel script attributes.
426
+ *
427
+ * @since 1.10.2
428
+ *
429
+ * @param array $custom_attributes
430
+ */
431
+ $custom_attributes = (array) apply_filters( 'wc_facebook_pixel_script_attributes', [ 'type' => 'text/javascript' ] );
432
+
433
+ foreach ( $custom_attributes as $tag => $value ) {
434
+ $script_attributes .= ' ' . $tag . '="' . esc_attr( $value ) . '"';
435
+ }
436
+
437
+ return $script_attributes;
438
+ }
439
+
440
+
441
public static function get_pixel_id() {
442
$fb_options = self::get_options();
443
if ( ! $fb_options ) {
480
update_option( self::SETTINGS_KEY, $fb_options );
481
}
482
483
private static function get_version_info() {
484
global $wp_version;
485
508
);
509
}
510
511
512
/**
513
+ * Gets Facebook Pixel base code.
514
+ *
515
+ * @deprecated since 1.10.2
516
+ *
517
+ * @return string
518
*/
519
+ public static function get_basecode() {
520
521
+ wc_deprecated_function( __METHOD__, '1.10.2' );
522
523
+ return '';
524
}
525
526
+
527
}
528
529
endif;
facebook-commerce.php CHANGED
@@ -76,6 +76,9 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
76
/** @var string the messenger color HEX setting ID */
77
const SETTING_MESSENGER_COLOR_HEX = 'messenger_color_hex';
78
79
/** @var string the standard product description mode name */
80
const PRODUCT_DESCRIPTION_MODE_STANDARD = 'standard';
81
@@ -324,7 +327,8 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
324
// Only load product processing hooks if we have completed setup.
325
if ( $this->get_page_access_token() && $this->get_product_catalog_id() ) {
326
327
- add_action( 'woocommerce_process_product_meta', [ $this, 'on_product_save' ], 20 );
328
329
add_action(
330
'woocommerce_product_quick_edit_save',
@@ -1311,6 +1315,11 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
1311
function update_product_item( $woo_product, $fb_product_item_id ) {
1312
$product_data = $woo_product->prepare_product();
1313
1314
$result = $this->check_api_result(
1315
$this->fbgraph->update_product_item(
1316
$fb_product_item_id,
@@ -1480,6 +1489,11 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
1480
$this->settings[ self::SETTING_ENABLE_ADVANCED_MATCHING ] = 'no';
1481
$this->settings[ self::SETTING_FACEBOOK_PAGE_ID ] = '';
1482
1483
$this->update_external_merchant_settings_id( '' );
1484
$this->update_pixel_install_time( 0 );
1485
$this->update_feed_id( '' );
@@ -1524,7 +1538,7 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
1524
'connected' => true,
1525
'status' => 'in progress',
1526
);
1527
- if ( $this->settings['fb_upload_id'] ) {
1528
if ( ! isset( $this->fbproductfeed ) ) {
1529
if ( ! class_exists( 'WC_Facebook_Product_Feed' ) ) {
1530
include_once 'includes/fbproductfeed.php';
@@ -1632,15 +1646,9 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
1632
*/
1633
function display_error_message( $msg ) {
1634
1635
- $msg = self::FB_ADMIN_MESSAGE_PREPEND . $msg;
1636
-
1637
WC_Facebookcommerce_Utils::log( $msg );
1638
1639
- set_transient(
1640
- 'facebook_plugin_api_error',
1641
- $msg,
1642
- self::FB_MESSAGE_DISPLAY_TIME
1643
- );
1644
}
1645
1646
@@ -2002,24 +2010,88 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
2002
2003
/**
2004
* Special function to run all visible products through on_product_publish
2005
- **/
2006
- function ajax_sync_all_fb_products() {
2007
WC_Facebookcommerce_Utils::check_woo_ajax_permissions( 'syncall products', true );
2008
check_ajax_referer( 'wc_facebook_settings_jsx' );
2009
2010
if ( ! $this->is_product_sync_enabled() ) {
2011
WC_Facebookcommerce_Utils::log( 'Sync to Facebook is disabled' );
2012
- wp_die();
2013
}
2014
2015
if ( ! $this->get_page_access_token() || ! $this->get_product_catalog_id() ) {
2016
- WC_Facebookcommerce_Utils::log(
2017
- 'No API key or catalog ID: ' .
2018
- $this->get_page_access_token() . ' and ' . $this->get_product_catalog_id()
2019
- );
2020
- wp_die();
2021
- return;
2022
}
2023
$this->remove_resync_message();
2024
2025
$currently_syncing = get_transient( self::FB_SYNC_IN_PROGRESS );
@@ -2032,40 +2104,27 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
2032
}
2033
2034
if ( $currently_syncing ) {
2035
- WC_Facebookcommerce_Utils::log( 'Not syncing, sync in progress' );
2036
WC_Facebookcommerce_Utils::fblog(
2037
'Tried to sync during an in-progress sync!',
2038
array(),
2039
true
2040
);
2041
- $this->display_warning_message(
2042
- 'A product sync is in progress.
2043
- Please wait until the sync finishes before starting a new one.'
2044
- );
2045
- wp_die();
2046
- return;
2047
}
2048
2049
- $is_valid_product_catalog =
2050
- $this->fbgraph->validate_product_catalog( $this->get_product_catalog_id() );
2051
2052
- if ( ! $is_valid_product_catalog ) {
2053
WC_Facebookcommerce_Utils::log( 'Not syncing, invalid product catalog!' );
2054
WC_Facebookcommerce_Utils::fblog(
2055
'Tried to sync with an invalid product catalog!',
2056
array(),
2057
true
2058
);
2059
- $this->display_warning_message(
2060
- 'We\'ve detected that your
2061
- Facebook Product Catalog is no longer valid. This may happen if it was
2062
- deleted, or this may be a transient error.
2063
- If this error persists please remove your settings via
2064
- "Advanced Options > Advanced Settings > Remove"
2065
- and try setup again'
2066
- );
2067
- wp_die();
2068
- return;
2069
}
2070
2071
// Cache the cart URL to display a warning in case it changes later
@@ -2167,21 +2226,23 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
2167
// https://codex.wordpress.org/Function_Reference/wp_reset_postdata
2168
wp_reset_postdata();
2169
2170
- // This is important, for some reason.
2171
- // See https://codex.wordpress.org/AJAX_in_Plugins
2172
- wp_die();
2173
}
2174
2175
/**
2176
* Special function to run all visible products by uploading feed.
2177
- **/
2178
- function ajax_sync_all_fb_products_using_feed() {
2179
WC_Facebookcommerce_Utils::check_woo_ajax_permissions(
2180
'syncall products using feed',
2181
! $this->test_mode
2182
);
2183
check_ajax_referer( 'wc_facebook_settings_jsx' );
2184
- return $this->sync_all_fb_products_using_feed();
2185
}
2186
2187
@@ -2190,42 +2251,38 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
2190
*
2191
* @see https://developers.facebook.com/docs/marketing-api/fbe/fbe1/guides/feed-approach
2192
*
2193
* @return bool
2194
*/
2195
- public function sync_all_fb_products_using_feed() {
2196
2197
if ( ! $this->is_product_sync_enabled() ) {
2198
WC_Facebookcommerce_Utils::log( 'Sync to Facebook is disabled' );
2199
- return false;
2200
}
2201
2202
if ( ! $this->get_page_access_token() || ! $this->get_product_catalog_id() ) {
2203
- self::log(
2204
- 'No API key or catalog ID: ' . $this->get_page_access_token() .
2205
- ' and ' . $this->get_product_catalog_id()
2206
- );
2207
- return false;
2208
}
2209
$this->remove_resync_message();
2210
- $is_valid_product_catalog =
2211
- $this->fbgraph->validate_product_catalog( $this->get_product_catalog_id() );
2212
2213
- if ( ! $is_valid_product_catalog ) {
2214
WC_Facebookcommerce_Utils::log( 'Not syncing, invalid product catalog!' );
2215
WC_Facebookcommerce_Utils::fblog(
2216
'Tried to sync with an invalid product catalog!',
2217
array(),
2218
true
2219
);
2220
- $this->display_warning_message(
2221
- 'We\'ve detected that your
2222
- Facebook Product Catalog is no longer valid. This may happen if it was
2223
- deleted, or this may be a transient error.
2224
- If this error persists please remove your settings via
2225
- "Advanced Options > Advanced Settings > Remove"
2226
- and try setup again'
2227
- );
2228
- return false;
2229
}
2230
2231
// Cache the cart URL to display a warning in case it changes later
@@ -2251,27 +2308,46 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
2251
);
2252
}
2253
2254
- $upload_success = $this->fbproductfeed->sync_all_products_using_feed();
2255
- if ( $upload_success ) {
2256
- $this->update_feed_id( $this->fbproductfeed->feed_id );
2257
- $this->settings['fb_upload_id'] = $this->fbproductfeed->upload_id;
2258
- update_option(
2259
- $this->get_option_key(),
2260
- apply_filters(
2261
- 'woocommerce_settings_api_sanitized_fields_' .
2262
- $this->id,
2263
- $this->settings
2264
- )
2265
- );
2266
- wp_reset_postdata();
2267
- return true;
2268
}
2269
- WC_Facebookcommerce_Utils::fblog(
2270
- 'Sync all products using feed, curl failed',
2271
- array(),
2272
- true
2273
);
2274
- return false;
2275
}
2276
2277
@@ -2328,6 +2404,9 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
2328
$default_locale = 'en_US';
2329
}
2330
2331
$form_fields = [
2332
2333
/** @see \WC_Facebookcommerce_Integration::generate_manage_connection_title_html() */
@@ -2444,6 +2523,9 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
2444
'class' => 'wc-enhanced-select messenger-field',
2445
'default' => $default_locale,
2446
'options' => $messenger_locales,
2447
],
2448
2449
/** @see \WC_Facebookcommerce_Integration::generate_messenger_greeting_html() */
@@ -2452,19 +2534,36 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
2452
'title' => __( 'Greeting', 'facebook-for-woocommerce' ),
2453
'type' => 'messenger_greeting',
2454
'class' => 'messenger-field',
2455
- 'default' => __( "Hi! We're here to answer any questions you may have.", 'facebook-for-woocommerce' ),
2456
'css' => 'max-width: 400px; margin-bottom: 10px',
2457
'custom_attributes' => [
2458
- 'maxlength' => $this->get_messenger_greeting_max_characters(),
2459
],
2460
],
2461
2462
self::SETTING_MESSENGER_COLOR_HEX => [
2463
- 'title' => __( 'Colors', 'facebook-for-woocommerce' ),
2464
- 'type' => 'color',
2465
- 'class' => 'messenger-field',
2466
- 'default' => '#0084ff',
2467
- 'css' => 'width: 6em;',
2468
],
2469
2470
];
@@ -2695,8 +2794,8 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
2695
href="#"
2696
style="vertical-align: middle; margin-left: 20px;"
2697
><?php esc_html_e( 'Sync products', 'facebook-for-woocommerce' ); ?></a>
2698
- <span id="sync_progress" style="margin-left: 10px"></span>
2699
</h3>
2700
<table class="form-table">
2701
<?php
2702
@@ -2726,6 +2825,66 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
2726
} elseif ( $saved_resync_offset !== $current_resync_offset || false === $this->is_resync_scheduled() ) {
2727
$this->schedule_resync( $saved_resync_offset );
2728
}
2729
}
2730
2731
@@ -3602,6 +3761,27 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
3602
}
3603
3604
3605
/**
3606
* Gets message HTML.
3607
*
@@ -3630,17 +3810,9 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
3630
*/
3631
public function maybe_display_facebook_api_messages() {
3632
3633
- $error_msg = get_transient( 'facebook_plugin_api_error' );
3634
3635
- if ( $error_msg ) {
3636
-
3637
- $message = sprintf(
3638
- __(
3639
- 'Facebook extension error: %s ',
3640
- 'facebook-for-woocommerce'
3641
- ),
3642
- $error_msg
3643
- );
3644
3645
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
3646
echo $this->get_message_html( $message );
@@ -4001,7 +4173,7 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
4001
4002
$body = WC_Facebookcommerce_Utils::decode_json( $product_fbid_result['body'] );
4003
4004
- if ( $body && $body->id ) {
4005
4006
if ( $fbid_type == self::FB_PRODUCT_GROUP_ID ) {
4007
$fb_id = $body->product_group->id;
@@ -4180,7 +4352,9 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
4180
*/
4181
public function handle_scheduled_resync_action() {
4182
4183
- $this->sync_all_fb_products_using_feed();
4184
4185
$resync_offset = $this->get_scheduled_resync_offset();
4186
76
/** @var string the messenger color HEX setting ID */
77
const SETTING_MESSENGER_COLOR_HEX = 'messenger_color_hex';
78
79
+ /** @var string the "debug mode" setting ID */
80
+ const SETTING_ENABLE_DEBUG_MODE = 'enable_debug_mode';
81
+
82
/** @var string the standard product description mode name */
83
const PRODUCT_DESCRIPTION_MODE_STANDARD = 'standard';
84
327
// Only load product processing hooks if we have completed setup.
328
if ( $this->get_page_access_token() && $this->get_product_catalog_id() ) {
329
330
+ // on_product_save() must run with priority larger than 20 to make sure WooCommerce has a chance to save the submitted product information
331
+ add_action( 'woocommerce_process_product_meta', [ $this, 'on_product_save' ], 40 );
332
333
add_action(
334
'woocommerce_product_quick_edit_save',
1315
function update_product_item( $woo_product, $fb_product_item_id ) {
1316
$product_data = $woo_product->prepare_product();
1317
1318
+ // send an empty string to clear the additional_image_urls property if the product has no additional images
1319
+ if ( empty( $product_data['additional_image_urls'] ) ) {
1320
+ $product_data['additional_image_urls'] = '';
1321
+ }
1322
+
1323
$result = $this->check_api_result(
1324
$this->fbgraph->update_product_item(
1325
$fb_product_item_id,
1489
$this->settings[ self::SETTING_ENABLE_ADVANCED_MATCHING ] = 'no';
1490
$this->settings[ self::SETTING_FACEBOOK_PAGE_ID ] = '';
1491
1492
+ unset( $this->settings[ self::SETTING_ENABLE_MESSENGER ] );
1493
+ unset( $this->settings[ self::SETTING_MESSENGER_GREETING ] );
1494
+ unset( $this->settings[ self::SETTING_MESSENGER_LOCALE ] );
1495
+ unset( $this->settings[ self::SETTING_MESSENGER_COLOR_HEX ] );
1496
+
1497
$this->update_external_merchant_settings_id( '' );
1498
$this->update_pixel_install_time( 0 );
1499
$this->update_feed_id( '' );
1538
'connected' => true,
1539
'status' => 'in progress',
1540
);
1541
+ if ( ! empty( $this->settings['fb_upload_id'] ) ) {
1542
if ( ! isset( $this->fbproductfeed ) ) {
1543
if ( ! class_exists( 'WC_Facebook_Product_Feed' ) ) {
1544
include_once 'includes/fbproductfeed.php';
1646
*/
1647
function display_error_message( $msg ) {
1648
1649
WC_Facebookcommerce_Utils::log( $msg );
1650
1651
+ set_transient( 'facebook_plugin_api_error', $msg, self::FB_MESSAGE_DISPLAY_TIME );
1652
}
1653
1654
2010
2011
/**
2012
* Special function to run all visible products through on_product_publish
2013
+ *
2014
+ * @internal
2015
+ */
2016
+ public function ajax_sync_all_fb_products() {
2017
+
2018
WC_Facebookcommerce_Utils::check_woo_ajax_permissions( 'syncall products', true );
2019
check_ajax_referer( 'wc_facebook_settings_jsx' );
2020
2021
+ $this->sync_facebook_products( 'background' );
2022
+ }
2023
+
2024
+
2025
+ /**
2026
+ * Syncs Facebook products using the GraphAPI.
2027
+ *
2028
+ * It can either use a Feed upload or update each product individually based on the selecetd method.
2029
+ * Ends the request sending a JSON response indicating success or failure.
2030
+ *
2031
+ * @since 1.10.2
2032
+ *
2033
+ * @param string $method either 'feed' or 'background'
2034
+ */
2035
+ private function sync_facebook_products( $method ) {
2036
+
2037
+ try {
2038
+
2039
+ if ( 'feed' === $method ) {
2040
+
2041
+ $this->sync_facebook_products_using_feed();
2042
+
2043
+ } elseif ( 'background' === $method ) {
2044
+
2045
+ // if syncs starts, the background processor will continue executing until the request ends and no response will be sent back to the browser
2046
+ $this->sync_facebook_products_using_background_processor();
2047
+ }
2048
+
2049
+ wp_send_json_success();
2050
+
2051
+ } catch ( Framework\SV_WC_Plugin_Exception $e ) {
2052
+
2053
+ // Access token has expired
2054
+ if ( 190 === $e->getCode() ) {
2055
+ $error_message = __( 'Your connection has expired.', 'facebook-for-woocommerce' ) . ' <strong>' . __( 'Please click Manage connection > Advanced Options > Update Token to refresh your connection to Facebook.', 'facebook-for-woocommerce' ) . '</strong>';
2056
+ } else {
2057
+ $error_message = $e->getMessage();
2058
+ }
2059
+
2060
+ $message = sprintf(
2061
+ /* translators: Placeholders %s - error message */
2062
+ __( 'There was an error trying to sync the products to Facebook. %s', 'facebook-for-woocommerce' ),
2063
+ $error_message
2064
+ );
2065
+
2066
+ wp_send_json_error( [ 'error' => $message ] );
2067
+ }
2068
+ }
2069
+
2070
+
2071
+ /**
2072
+ * Syncs Facebook products using the background processor.
2073
+ *
2074
+ * @since 1.10.2
2075
+ *
2076
+ * @throws Framework\SV_WC_Plugin_Exception
2077
+ * @return bool
2078
+ */
2079
+ private function sync_facebook_products_using_background_processor() {
2080
+
2081
if ( ! $this->is_product_sync_enabled() ) {
2082
+
2083
WC_Facebookcommerce_Utils::log( 'Sync to Facebook is disabled' );
2084
+
2085
+ throw new Framework\SV_WC_Plugin_Exception( __( 'Product sync is disabled.', 'facebook-for-woocommerce' ) );
2086
}
2087
2088
if ( ! $this->get_page_access_token() || ! $this->get_product_catalog_id() ) {
2089
+
2090
+ WC_Facebookcommerce_Utils::log( sprintf( 'No API key or Catalog ID: %s and %s', $this->get_page_access_token(), $this->get_product_catalog_id() ) );
2091
+
2092
+ throw new Framework\SV_WC_Plugin_Exception( __( 'The page access token or product catalog ID are missing.', 'facebook-for-woocommerce' ) );
2093
}
2094
+
2095
$this->remove_resync_message();
2096
2097
$currently_syncing = get_transient( self::FB_SYNC_IN_PROGRESS );
2104
}
2105
2106
if ( $currently_syncing ) {
2107
+
2108
+ WC_Facebookcommerce_Utils::log( 'Not syncing again, sync already in progress' );
2109
WC_Facebookcommerce_Utils::fblog(
2110
'Tried to sync during an in-progress sync!',
2111
array(),
2112
true
2113
);
2114
+
2115
+ throw new Framework\SV_WC_Plugin_Exception( __( 'A product sync is in progress. Please wait until the sync finishes before starting a new one.', 'facebook-for-woocommerce' ) );
2116
}
2117
2118
+ if ( ! $this->fbgraph->is_product_catalog_valid( $this->get_product_catalog_id() ) ) {
2119
2120
WC_Facebookcommerce_Utils::log( 'Not syncing, invalid product catalog!' );
2121
WC_Facebookcommerce_Utils::fblog(
2122
'Tried to sync with an invalid product catalog!',
2123
array(),
2124
true
2125
);
2126
+
2127
+ throw new Framework\SV_WC_Plugin_Exception( __( "We've detected that your Facebook Product Catalog is no longer valid. This may happen if it was deleted, but could also be a temporary error. If the error persists, please click Manage connection > Advanced Options > Remove and setup the plugin again.", 'facebook-for-woocommerce' ) );
2128
}
2129
2130
// Cache the cart URL to display a warning in case it changes later
2226
// https://codex.wordpress.org/Function_Reference/wp_reset_postdata
2227
wp_reset_postdata();
2228
2229
+ return true;
2230
}
2231
2232
+
2233
/**
2234
* Special function to run all visible products by uploading feed.
2235
+ *
2236
+ * @internal
2237
+ */
2238
+ public function ajax_sync_all_fb_products_using_feed() {
2239
WC_Facebookcommerce_Utils::check_woo_ajax_permissions(
2240
'syncall products using feed',
2241
! $this->test_mode
2242
);
2243
check_ajax_referer( 'wc_facebook_settings_jsx' );
2244
+
2245
+ $this->sync_facebook_products( 'feed' );
2246
}
2247
2248
2251
*
2252
* @see https://developers.facebook.com/docs/marketing-api/fbe/fbe1/guides/feed-approach
2253
*
2254
+ * @since 1.10.2
2255
+ *
2256
+ * @throws Framework\SV_WC_Plugin_Exception
2257
* @return bool
2258
*/
2259
+ public function sync_facebook_products_using_feed() {
2260
2261
if ( ! $this->is_product_sync_enabled() ) {
2262
WC_Facebookcommerce_Utils::log( 'Sync to Facebook is disabled' );
2263
+
2264
+ throw new Framework\SV_WC_Plugin_Exception( __( 'Product sync is disabled.', 'facebook-for-woocommerce' ) );
2265
}
2266
2267
if ( ! $this->get_page_access_token() || ! $this->get_product_catalog_id() ) {
2268
+
2269
+ WC_Facebookcommerce_Utils::log( sprintf( 'No API key or Catalog ID: %s and %s', $this->get_page_access_token(), $this->get_product_catalog_id() ) );
2270
+
2271
+ throw new Framework\SV_WC_Plugin_Exception( __( 'The page access token or product catalog ID are missing.', 'facebook-for-woocommerce' ) );
2272
}
2273
+
2274
$this->remove_resync_message();
2275
2276
+ if ( ! $this->fbgraph->is_product_catalog_valid( $this->get_product_catalog_id() ) ) {
2277
+
2278
WC_Facebookcommerce_Utils::log( 'Not syncing, invalid product catalog!' );
2279
WC_Facebookcommerce_Utils::fblog(
2280
'Tried to sync with an invalid product catalog!',
2281
array(),
2282
true
2283
);
2284
+
2285
+ throw new Framework\SV_WC_Plugin_Exception( __( "We've detected that your Facebook Product Catalog is no longer valid. This may happen if it was deleted, but could also be a temporary error. If the error persists, please click Manage connection > Advanced Options > Remove and setup the plugin again.", 'facebook-for-woocommerce' ) );
2286
}
2287
2288
// Cache the cart URL to display a warning in case it changes later
2308
);
2309
}
2310
2311
+ if ( ! $this->fbproductfeed->sync_all_products_using_feed() ) {
2312
+
2313
+ WC_Facebookcommerce_Utils::fblog( 'Sync all products using feed, curl failed', [], true );
2314
+
2315
+ throw new Framework\SV_WC_Plugin_Exception( __( "We couldn't create the feed or upload the product information.", 'facebook-for-woocommerce' ) );
2316
}
2317
+
2318
+ $this->update_feed_id( $this->fbproductfeed->feed_id );
2319
+
2320
+ $this->settings['fb_upload_id'] = $this->fbproductfeed->upload_id;
2321
+
2322
+ update_option(
2323
+ $this->get_option_key(),
2324
+ apply_filters( 'woocommerce_settings_api_sanitized_fields_' . $this->id, $this->settings )
2325
);
2326
+
2327
+ wp_reset_postdata();
2328
+
2329
+ return true;
2330
+ }
2331
+
2332
+
2333
+ /**
2334
+ * Syncs Facebook products using a Feed.
2335
+ *
2336
+ * TODO: deprecate this methid in 1.11.0 or newer {WV 2020-03-12}
2337
+ *
2338
+ * @see https://developers.facebook.com/docs/marketing-api/fbe/fbe1/guides/feed-approach
2339
+ *
2340
+ * @return bool
2341
+ */
2342
+ public function sync_all_fb_products_using_feed() {
2343
+
2344
+ try {
2345
+ $sync_started = $this->sync_facebook_products_using_feed();
2346
+ } catch ( Framework\SV_WC_Plugin_Exception $e ) {
2347
+ $sync_started = false;
2348
+ }
2349
+
2350
+ return $sync_started;
2351
}
2352
2353
2404
$default_locale = 'en_US';
2405
}
2406
2407
+ $default_messenger_greeting = __( "Hi! We're here to answer any questions you may have.", 'facebook-for-woocommerce' );
2408
+ $default_messenger_color = '#0084ff';
2409
+
2410
$form_fields = [
2411
2412
/** @see \WC_Facebookcommerce_Integration::generate_manage_connection_title_html() */
2523
'class' => 'wc-enhanced-select messenger-field',
2524
'default' => $default_locale,
2525
'options' => $messenger_locales,
2526
+ 'custom_attributes' => [
2527
+ 'data-default' => $default_locale,
2528
+ ],
2529
],
2530
2531
/** @see \WC_Facebookcommerce_Integration::generate_messenger_greeting_html() */
2534
'title' => __( 'Greeting', 'facebook-for-woocommerce' ),
2535
'type' => 'messenger_greeting',
2536
'class' => 'messenger-field',
2537
+ 'default' => $default_messenger_greeting,
2538
'css' => 'max-width: 400px; margin-bottom: 10px',
2539
'custom_attributes' => [
2540
+ 'maxlength' => $this->get_messenger_greeting_max_characters(),
2541
+ 'data-default' => $default_messenger_greeting,
2542
],
2543
],
2544
2545
self::SETTING_MESSENGER_COLOR_HEX => [
2546
+ 'title' => __( 'Colors', 'facebook-for-woocommerce' ),
2547
+ 'type' => 'color',
2548
+ 'class' => 'messenger-field',
2549
+ 'default' => $default_messenger_color,
2550
+ 'css' => 'width: 6em;',
2551
+ 'custom_attributes' => [
2552
+ 'data-default' => $default_messenger_color,
2553
+ ],
2554
+ ],
2555
+
2556
+ [
2557
+ 'title' => __( 'Debug', 'facebook-for-woocommerce' ),
2558
+ 'type' => 'title',
2559
+ ],
2560
+
2561
+ self::SETTING_ENABLE_DEBUG_MODE => [
2562
+ 'title' => __( 'Enable debug mode', 'facebook-for-woocommerce' ),
2563
+ 'type' => 'checkbox',
2564
+ 'label' => __( 'Log plugin events for debugging', 'facebook-for-woocommerce' ),
2565
+ 'desc_tip' => __( 'Only enable this if you are experiencing problems with the plugin.', 'facebook-for-woocommerce' ),
2566
+ 'default' => 'no',
2567
],
2568
2569
];
2794
href="#"
2795
style="vertical-align: middle; margin-left: 20px;"
2796
><?php esc_html_e( 'Sync products', 'facebook-for-woocommerce' ); ?></a>
2797
</h3>
2798
+ <div><p id="sync_progress" style="display: none"></p></div>
2799
<table class="form-table">
2800
<?php
2801
2825
} elseif ( $saved_resync_offset !== $current_resync_offset || false === $this->is_resync_scheduled() ) {
2826
$this->schedule_resync( $saved_resync_offset );
2827
}
2828
+
2829
+ // when settings are saved, if there are excluded categories/terms we can exclude corresponding products from sync
2830
+ $product_cats = $product_tags = [];
2831
+ $product_cat_ids = $this->get_excluded_product_category_ids();
2832
+ $product_tag_ids = $this->get_excluded_product_tag_ids();
2833
+
2834
+ $disable_sync_for_products = [];
2835
+
2836
+ // get all products belonging to excluded categories
2837
+ if ( ! empty( $product_cat_ids ) ) {
2838
+
2839
+ foreach ( $product_cat_ids as $tag_id ) {
2840
+
2841
+ $term = get_term_by( 'id', $tag_id, 'product_cat' );
2842
+
2843
+ if ( $term instanceof \WP_Term ) {
2844
+ $product_cats[] = $term->slug;
2845
+ }
2846
+ }
2847
+
2848
+ if ( ! empty( $product_cats ) ) {
2849
+
2850
+ $disable_sync_for_products = wc_get_products( [
2851
+ 'category' => $product_cats,
2852
+ 'limit' => -1,
2853
+ 'return' => 'ids',
2854
+ ] );
2855
+ }
2856
+ }
2857
+
2858
+ // get all products belonging to excluded tags
2859
+ if ( ! empty( $product_tag_ids ) ) {
2860
+
2861
+ foreach ( $product_tag_ids as $tag_id ) {
2862
+
2863
+ $term = get_term_by( 'id', $tag_id, 'product_tag' );
2864
+
2865
+ if ( $term instanceof \WP_Term ) {
2866
+ $product_tags[] = $term->slug;
2867
+ }
2868
+ }
2869
+
2870
+ if ( ! empty( $product_tags ) ) {
2871
+
2872
+ $disable_sync_for_products = array_merge( wc_get_products( [
2873
+ 'tag' => $product_tags,
2874
+ 'limit' => -1,
2875
+ 'return' => 'ids',
2876
+ ] ), $disable_sync_for_products );
2877
+ }
2878
+ }
2879
+
2880
+ if ( ! empty( $disable_sync_for_products ) ) {
2881
+
2882
+ // disable sync for found products that match any excluded term
2883
+ Products::disable_sync_for_products( wc_get_products( [
2884
+ 'limit' => -1,
2885
+ 'include' => array_unique( $disable_sync_for_products ),
2886
+ ] ) );
2887
+ }
2888
}
2889
2890
3761
}
3762
3763
3764
+ /**
3765
+ * Determines whether debug mode is enabled.
3766
+ *
3767
+ * @since 1.10.2
3768
+ *
3769
+ * @return bool
3770
+ */
3771
+ public function is_debug_mode_enabled() {
3772
+
3773
+ /**
3774
+ * Filters whether debug mode is enabled.
3775
+ *
3776
+ * @since 1.10.2
3777
+ *
3778
+