Facebook for WooCommerce - Version 2.3.0

Version Description

Download this release

Release Info

Developer automattic
Plugin Icon Facebook for WooCommerce
Version 2.3.0
Comparing to
See all releases

Code changes from version 2.2.0 to 2.3.0

Files changed (34) hide show
  1. assets/css/admin/facebook-for-woocommerce-product-sets-admin.css +16 -0
  2. assets/css/admin/facebook-for-woocommerce-products-admin.css +4 -0
  3. assets/js/admin/facebook-for-woocommerce-product-sets-admin.js +30 -0
  4. assets/js/admin/facebook-for-woocommerce-product-sets-admin.min.js +1 -0
  5. assets/js/admin/facebook-for-woocommerce-products-admin.js +192 -24
  6. assets/js/admin/facebook-for-woocommerce-products-admin.min.js +1 -1
  7. assets/js/admin/facebook-for-woocommerce-products-admin.min.old.min.js +1 -1
  8. assets/js/admin/facebook-for-woocommerce-settings-sync.min.js +1 -1
  9. assets/js/admin/orders.min.js +1 -1
  10. assets/js/facebook-for-woocommerce-modal.js +9 -0
  11. assets/js/facebook-for-woocommerce-modal.min.js +1 -1
  12. changelog.txt +10 -0
  13. class-wc-facebookcommerce.php +176 -15
  14. facebook-commerce.php +134 -4
  15. facebook-for-woocommerce.php +2 -2
  16. i18n/languages/facebook-for-woocommerce.pot +179 -95
  17. includes/API.php +0 -19
  18. includes/API/Business_Manager/Request.php +0 -51
  19. includes/API/Business_Manager/Response.php +0 -49
  20. includes/API/FBE/Installation/Read/Response.php +32 -0
  21. includes/Admin.php +115 -15
  22. includes/Admin/Product_Categories.php +1 -1
  23. includes/Admin/Product_Sets.php +184 -0
  24. includes/Admin/Settings.php +1 -0
  25. includes/Admin/Settings_Screens/Connection.php +8 -18
  26. includes/Admin/Settings_Screens/Product_Sets.php +43 -0
  27. includes/Handlers/Connection.php +355 -1
  28. includes/Handlers/WebHook.php +97 -0
  29. includes/ProductSets/Sync.php +441 -0
  30. includes/Product_Categories.php +3 -3
  31. includes/Products.php +14 -2
  32. includes/fbgraph.php +25 -4
  33. includes/fbproduct.php +10 -1
  34. readme.txt +12 -2
assets/css/admin/facebook-for-woocommerce-product-sets-admin.css ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ body.taxonomy-fb_product_set .term-parent-wrap,
2
+ body.taxonomy-fb_product_set .term-slug-wrap {
3
+ display: none;
4
+ }
5
+
6
+ .wc-facebook.product_cats.select2.visible {
7
+ display: block;
8
+ }
9
+
10
+ body.taxonomy-fb_product_set .select2-container {
11
+ display: table;
12
+ margin-bottom: 0;
13
+ position: relative;
14
+ table-layout: fixed;
15
+ width: 95% !important;
16
+ }
assets/css/admin/facebook-for-woocommerce-products-admin.css CHANGED
@@ -1,3 +1,7 @@
 
 
 
 
1
  #woocommerce-product-data .fb-product-image-source-field .wc-radios {
2
  width: auto;
3
  }
1
+ #newfb_product_set_parent {
2
+ display: none;
3
+ }
4
+
5
  #woocommerce-product-data .fb-product-image-source-field .wc-radios {
6
  width: auto;
7
  }
assets/js/admin/facebook-for-woocommerce-product-sets-admin.js ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
3
+ *
4
+ * This source code is licensed under the license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @package FacebookCommerce
8
+ */
9
+
10
+ jQuery( document ).ready( function( $ ) {
11
+
12
+ if ( jQuery( '.select2.wc-facebook' ).length ) {
13
+ wcFacebookProductSetInit();
14
+ }
15
+
16
+ function wcFacebookProductSetInit() {
17
+
18
+ jQuery( '.select2.wc-facebook' ).select2().addClass( 'visible' ).attr( 'disabled', false );
19
+ jQuery( '.select2.updating-message' ).addClass( 'hidden' );
20
+
21
+ jQuery( document ).ajaxSuccess( function( e, request, settings ) {
22
+ var obj = new URLSearchParams( settings.data )
23
+ if ( obj.has( 'action' ) && 'add-tag' === obj.get( 'action' ) && obj.has( 'taxonomy' ) && 'fb_product_set' === obj.get( 'taxonomy' ) ) {
24
+ jQuery( '.select2.wc-facebook' ).select2().val( null ).trigger( 'change' );
25
+ }
26
+ });
27
+
28
+ }
29
+
30
+ } );
assets/js/admin/facebook-for-woocommerce-product-sets-admin.min.js ADDED
@@ -0,0 +1 @@
 
1
+ "use strict";jQuery(document).ready(function(e){jQuery(".select2.wc-facebook").length&&(jQuery(".select2.wc-facebook").select2().addClass("visible").attr("disabled",!1),jQuery(".select2.updating-message").addClass("hidden"),jQuery(document).ajaxSuccess(function(e,a,t){t=new URLSearchParams(t.data);t.has("action")&&"add-tag"===t.get("action")&&t.has("taxonomy")&&"fb_product_set"===t.get("taxonomy")&&jQuery(".select2.wc-facebook").select2().val(null).trigger("change")}))});
assets/js/admin/facebook-for-woocommerce-products-admin.js CHANGED
@@ -47,8 +47,7 @@ jQuery( document ).ready( function( $ ) {
47
 
48
  if ( response && ! response.success ) {
49
 
50
- // close existing modals
51
- $( '#wc-backbone-modal-dialog .modal-close' ).trigger( 'click' );
52
 
53
  // open new modal, populate template with AJAX response data
54
  new $.WCBackboneModal.View( {
@@ -249,7 +248,7 @@ jQuery( document ).ready( function( $ ) {
249
  */
250
  function isSyncEnabledForSimpleProduct() {
251
 
252
- return $( '#wc_facebook_sync_mode' ).val() !== 'sync_disabled';
253
  }
254
 
255
 
@@ -370,6 +369,151 @@ jQuery( document ).ready( function( $ ) {
370
  }
371
 
372
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
373
  // handle change events for the Sell on Instagram checkbox field
374
  $( '#facebook_options #wc_facebook_commerce_enabled' ).on( 'change', function() {
375
 
@@ -393,26 +537,39 @@ jQuery( document ).ready( function( $ ) {
393
  } ).trigger( 'change' );
394
 
395
  // toggle Facebook settings fields for simple products
396
- const syncModeSelect = $( '#wc_facebook_sync_mode' );
397
- const facebookSettingsPanel = syncModeSelect.closest( '.woocommerce_options_panel' );
398
 
399
- syncModeSelect.on( 'change', function() {
 
400
 
401
- let syncEnabled = $( this ).val() !== 'sync_disabled';
 
 
402
 
403
  toggleFacebookSettings( syncEnabled, facebookSettingsPanel );
404
  toggleFacebookCommerceSettings( syncEnabled, facebookSettingsPanel );
405
 
406
- syncModeSelect.prop( 'original', $( this ).val() );
 
 
 
 
 
 
 
 
407
 
408
  } ).trigger( 'change' );
409
 
410
  $( '#_virtual' ).on( 'change', function () {
411
- toggleSyncAndShowOption( ! $( this ).prop( 'checked' ), syncModeSelect );
412
  } ).trigger( 'change' );
413
 
 
 
414
  // check whether the product meets the requirements for Commerce
415
- $( '#woocommerce-product-data' ).on(
416
  'change',
417
  '#_regular_price, #_manage_stock, #_stock, #wc_facebook_sync_mode, #fb_product_price',
418
  function( event ) {
@@ -425,19 +582,32 @@ jQuery( document ).ready( function( $ ) {
425
  );
426
 
427
  // toggle Facebook settings fields for variations
428
- $( '.woocommerce_variations' ).on( 'change', '.js-variable-fb-sync-toggle', function() {
429
 
430
- toggleFacebookSettings( $( this ).val() !== 'sync_disabled', $( this ).closest( '.wc-metabox-content' ) );
 
 
 
431
  toggleFacebookSellOnInstagramSetting( isProductReadyForCommerce(), $( '#facebook_options' ) );
432
 
433
- $( this ).prop( 'original', $( this ).val() );
 
 
 
 
 
 
 
 
434
  } );
435
 
436
- $( '#woocommerce-product-data' ).on( 'woocommerce_variations_loaded', function () {
437
 
438
- $( '.js-variable-fb-sync-toggle' ).each( function () {
439
- toggleFacebookSettings( $( this ).val() !== 'sync_disabled', $( this ).closest( '.wc-metabox-content' ) );
440
- $( this ).prop( 'original', $( this ).val() );
 
 
441
  } );
442
 
443
  $( '.variable_is_virtual' ).on( 'change', function () {
@@ -449,7 +619,7 @@ jQuery( document ).ready( function( $ ) {
449
  } );
450
 
451
  // show/hide Custom Image URL setting
452
- $( '#woocommerce-product-data' ).on( 'change', '.js-fb-product-image-source', function() {
453
 
454
  let $container = $( this ).closest( '.woocommerce_options_panel, .wc-metabox-content' );
455
  let imageSource = $( this ).val();
@@ -461,7 +631,7 @@ jQuery( document ).ready( function( $ ) {
461
  $( '.js-fb-product-image-source:checked:visible' ).trigger( 'change' );
462
 
463
  // trigger settings fields modifiers when variations are loaded
464
- $( '#woocommerce-product-data' ).on( 'woocommerce_variations_loaded', function() {
465
  $( '.js-variable-fb-sync-toggle:visible' ).trigger( 'change' );
466
  $( '.js-fb-product-image-source:checked:visible' ).trigger( 'change' );
467
  $( '.variable_is_virtual:visible' ).trigger( 'change' );
@@ -472,8 +642,7 @@ jQuery( document ).ready( function( $ ) {
472
 
473
  event.preventDefault();
474
 
475
- // close existing modals
476
- $( '#wc-backbone-modal-dialog .modal-close' ).trigger( 'click' );
477
 
478
  new $.WCBackboneModal.View( {
479
  target: 'facebook-for-woocommerce-modal',
@@ -506,7 +675,7 @@ jQuery( document ).ready( function( $ ) {
506
  productCat = [],
507
  // this query will get tags when not using checkboxes
508
  productTag = $( 'textarea[name="tax_input[product_tag]"]' ).length ? $( 'textarea[name="tax_input[product_tag]"]' ).val().split( ',' ) : [],
509
- syncEnabled = $( '#wc_facebook_sync_mode' ).val() !== 'sync_disabled',
510
  varSyncEnabled = isSyncEnabledForVariableProduct();
511
 
512
  $( '#taxonomy-product_cat input[name="tax_input[product_cat][]"]:checked' ).each( function() {
@@ -533,8 +702,7 @@ jQuery( document ).ready( function( $ ) {
533
  // open modal if visibility checkbox is checked or if there are conflicting terms set for sync exclusion
534
  if ( response && ! response.success && syncEnabled ) {
535
 
536
- // close existing modals
537
- $( '#wc-backbone-modal-dialog .modal-close' ).trigger( 'click' );
538
 
539
  // open new modal, populate template with AJAX response data
540
  new $.WCBackboneModal.View( {
47
 
48
  if ( response && ! response.success ) {
49
 
50
+ closeExistingModal();
 
51
 
52
  // open new modal, populate template with AJAX response data
53
  new $.WCBackboneModal.View( {
248
  */
249
  function isSyncEnabledForSimpleProduct() {
250
 
251
+ return simpleProductSyncModeSelect.val() !== 'sync_disabled';
252
  }
253
 
254
 
369
  }
370
 
371
 
372
+ /**
373
+ * Store the original value of the given element for later use.
374
+ *
375
+ * @since 2.3.0
376
+ *
377
+ * @param {jQuery} $syncModeSelect a jQuery element object
378
+ */
379
+ function storeSyncModeOriginalValue( $syncModeSelect ) {
380
+
381
+ $syncModeSelect.attr( 'data-original-value', $syncModeSelect.val() );
382
+ }
383
+
384
+
385
+ /**
386
+ * Reverts the value of the given sync mode element to its original value.
387
+ *
388
+ * @since 2.3.0
389
+ *
390
+ * @param {jQuery} $syncModeSelect a jQuery element object
391
+ */
392
+ function revertSyncModeToOriginalValue( $syncModeSelect ) {
393
+
394
+ $syncModeSelect.val( $syncModeSelect.attr( 'data-original-value') );
395
+ }
396
+
397
+
398
+ /**
399
+ * Determines whether we should show the product removed from sync confirm modal.
400
+ *
401
+ * @since 2.3.0
402
+ *
403
+ * @param {jQuery} $syncModeSelect a jQuery object with one or more sync mode select elements
404
+ * @return {boolean}
405
+ */
406
+ function shouldShowProductRemovedFromSyncConfirmModal( $syncModeSelect ) {
407
+
408
+ let syncValuesStatus = $syncModeSelect.map( function ( index, selectElement ) {
409
+
410
+ let $syncMode = $( selectElement );
411
+ let syncModeValue = $syncMode.val();
412
+
413
+ return 'sync_disabled' === syncModeValue && syncModeValue !== $syncMode.attr( 'data-original-value' );
414
+ } ).toArray();
415
+
416
+ return syncValuesStatus.indexOf( true ) > -1;
417
+ }
418
+
419
+
420
+ /**
421
+ * Gets the target product ID based on the given sync select element.
422
+ *
423
+ * @since 2.3.0
424
+ *
425
+ * @param {jQuery} $syncModeSelect a jQuery element object
426
+ */
427
+ function getSyncTargetProductID( $syncModeSelect ) {
428
+
429
+ if ( simpleProductSyncModeSelect === $syncModeSelect ) {
430
+ // simple product
431
+ return $( 'input#post_ID' ).val();
432
+ }
433
+
434
+ // variable product
435
+ return $syncModeSelect.closest( '.woocommerce_variation' ).find( 'input[name^=variable_post_id]' ).val();
436
+ }
437
+
438
+
439
+ /**
440
+ * Shows the product removed from sync confirm modal.
441
+ *
442
+ * @since 2.3.0
443
+ *
444
+ * @param {jQuery} $syncModeSelect a jQuery element object
445
+ */
446
+ function showProductRemovedFromSyncConfirmModal( $syncModeSelect ) {
447
+
448
+ closeExistingModal();
449
+
450
+ $maybeRemoveFromSyncModeSelect = $syncModeSelect;
451
+ maybeRemoveFromSyncProductID = getSyncTargetProductID( $syncModeSelect )
452
+
453
+ new $.WCBackboneModal.View( {
454
+ target: 'facebook-for-woocommerce-modal',
455
+ string: {
456
+ message: facebook_for_woocommerce_products_admin.product_removed_from_sync_confirm_modal_message,
457
+ buttons: facebook_for_woocommerce_products_admin.product_removed_from_sync_confirm_modal_buttons
458
+ }
459
+ } );
460
+ }
461
+
462
+
463
+ /**
464
+ * Fills in product IDs to remove from Sync.
465
+ *
466
+ * @since 2.3.0
467
+ */
468
+ function populateRemoveFromSyncProductIDsField() {
469
+
470
+ $( facebook_for_woocommerce_products_admin.product_removed_from_sync_field_id ).val( removeFromSyncProductIDs.join( ',' ) );
471
+ }
472
+
473
+
474
+ /**
475
+ * Removes the given product ID from the list of product to delete from Sync.
476
+ *
477
+ * @since 2.3.0
478
+ *
479
+ * @param {String} productID Product ID to remove
480
+ */
481
+ function removeProductIDFromUnSyncList( productID ) {
482
+
483
+ removeFromSyncProductIDs = removeFromSyncProductIDs.filter( function ( value ) {
484
+ return value !== productID;
485
+ } );
486
+
487
+ populateRemoveFromSyncProductIDsField();
488
+ }
489
+
490
+ let $maybeRemoveFromSyncModeSelect = null;
491
+ let maybeRemoveFromSyncProductID = null;
492
+ let removeFromSyncProductIDs = [];
493
+
494
+ $( document.body ).on( 'click', 'button.button-product-removed-from-sync-delete', function () {
495
+
496
+ if ( maybeRemoveFromSyncProductID ) {
497
+
498
+ closeExistingModal();
499
+
500
+ removeFromSyncProductIDs.push( maybeRemoveFromSyncProductID );
501
+
502
+ populateRemoveFromSyncProductIDsField();
503
+ }
504
+ } )
505
+ .on( 'click', 'button.button-product-removed-from-sync-cancel', function () {
506
+
507
+ closeExistingModal();
508
+
509
+ if ( $maybeRemoveFromSyncModeSelect ) {
510
+ revertSyncModeToOriginalValue( $maybeRemoveFromSyncModeSelect );
511
+ $maybeRemoveFromSyncModeSelect = null;
512
+ }
513
+
514
+ populateRemoveFromSyncProductIDsField();
515
+ } );
516
+
517
  // handle change events for the Sell on Instagram checkbox field
518
  $( '#facebook_options #wc_facebook_commerce_enabled' ).on( 'change', function() {
519
 
537
  } ).trigger( 'change' );
538
 
539
  // toggle Facebook settings fields for simple products
540
+ const simpleProductSyncModeSelect = $( '#wc_facebook_sync_mode' );
541
+ const facebookSettingsPanel = simpleProductSyncModeSelect.closest( '.woocommerce_options_panel' );
542
 
543
+ // store sync mode original value for later use
544
+ storeSyncModeOriginalValue( simpleProductSyncModeSelect );
545
 
546
+ simpleProductSyncModeSelect.on( 'change', function() {
547
+
548
+ let syncEnabled = simpleProductSyncModeSelect.val() !== 'sync_disabled';
549
 
550
  toggleFacebookSettings( syncEnabled, facebookSettingsPanel );
551
  toggleFacebookCommerceSettings( syncEnabled, facebookSettingsPanel );
552
 
553
+ if ( syncEnabled ) {
554
+ removeProductIDFromUnSyncList( getSyncTargetProductID( simpleProductSyncModeSelect ) );
555
+ }
556
+
557
+ simpleProductSyncModeSelect.prop( 'original', simpleProductSyncModeSelect.val() );
558
+
559
+ if ( shouldShowProductRemovedFromSyncConfirmModal( simpleProductSyncModeSelect ) ) {
560
+ showProductRemovedFromSyncConfirmModal( simpleProductSyncModeSelect );
561
+ }
562
 
563
  } ).trigger( 'change' );
564
 
565
  $( '#_virtual' ).on( 'change', function () {
566
+ toggleSyncAndShowOption( ! $( this ).prop( 'checked' ), simpleProductSyncModeSelect );
567
  } ).trigger( 'change' );
568
 
569
+ const $productData = $( '#woocommerce-product-data' );
570
+
571
  // check whether the product meets the requirements for Commerce
572
+ $productData.on(
573
  'change',
574
  '#_regular_price, #_manage_stock, #_stock, #wc_facebook_sync_mode, #fb_product_price',
575
  function( event ) {
582
  );
583
 
584
  // toggle Facebook settings fields for variations
585
+ $( '.woocommerce_variations' ).on( 'change', '.js-variable-fb-sync-toggle', function () {
586
 
587
+ let $syncModeSelect = $( this );
588
+ let syncEnabled = $syncModeSelect.val() !== 'sync_disabled';
589
+
590
+ toggleFacebookSettings( syncEnabled, $syncModeSelect.closest( '.wc-metabox-content' ) );
591
  toggleFacebookSellOnInstagramSetting( isProductReadyForCommerce(), $( '#facebook_options' ) );
592
 
593
+ if ( syncEnabled ) {
594
+ removeProductIDFromUnSyncList( getSyncTargetProductID( $syncModeSelect ) );
595
+ }
596
+
597
+ $syncModeSelect.prop( 'original', $syncModeSelect.val() );
598
+
599
+ if ( shouldShowProductRemovedFromSyncConfirmModal( $syncModeSelect ) ) {
600
+ showProductRemovedFromSyncConfirmModal( $syncModeSelect );
601
+ }
602
  } );
603
 
604
+ $productData.on( 'woocommerce_variations_loaded', function () {
605
 
606
+ $productData.find( '.js-variable-fb-sync-toggle' ).each( function ( index, element ) {
607
+ let $syncModeSelect = $( element );
608
+ toggleFacebookSettings( $syncModeSelect.val() !== 'sync_disabled', $syncModeSelect.closest( '.wc-metabox-content' ) );
609
+ $syncModeSelect.prop( 'original', $syncModeSelect.val() );
610
+ storeSyncModeOriginalValue( $syncModeSelect );
611
  } );
612
 
613
  $( '.variable_is_virtual' ).on( 'change', function () {
619
  } );
620
 
621
  // show/hide Custom Image URL setting
622
+ $productData.on( 'change', '.js-fb-product-image-source', function() {
623
 
624
  let $container = $( this ).closest( '.woocommerce_options_panel, .wc-metabox-content' );
625
  let imageSource = $( this ).val();
631
  $( '.js-fb-product-image-source:checked:visible' ).trigger( 'change' );
632
 
633
  // trigger settings fields modifiers when variations are loaded
634
+ $productData.on( 'woocommerce_variations_loaded', function() {
635
  $( '.js-variable-fb-sync-toggle:visible' ).trigger( 'change' );
636
  $( '.js-fb-product-image-source:checked:visible' ).trigger( 'change' );
637
  $( '.variable_is_virtual:visible' ).trigger( 'change' );
642
 
643
  event.preventDefault();
644
 
645
+ closeExistingModal();
 
646
 
647
  new $.WCBackboneModal.View( {
648
  target: 'facebook-for-woocommerce-modal',
675
  productCat = [],
676
  // this query will get tags when not using checkboxes
677
  productTag = $( 'textarea[name="tax_input[product_tag]"]' ).length ? $( 'textarea[name="tax_input[product_tag]"]' ).val().split( ',' ) : [],
678
+ syncEnabled = simpleProductSyncModeSelect.val() !== 'sync_disabled',
679
  varSyncEnabled = isSyncEnabledForVariableProduct();
680
 
681
  $( '#taxonomy-product_cat input[name="tax_input[product_cat][]"]:checked' ).each( function() {
702
  // open modal if visibility checkbox is checked or if there are conflicting terms set for sync exclusion
703
  if ( response && ! response.success && syncEnabled ) {
704
 
705
+ closeExistingModal();
 
706
 
707
  // open new modal, populate template with AJAX response data
708
  new $.WCBackboneModal.View( {
assets/js/admin/facebook-for-woocommerce-products-admin.min.js CHANGED
@@ -1 +1 @@
1
- "use strict";jQuery(document).ready(function(r){var t,e,c,n,i,o,s,a,_,d,l,u,p,f,m,g,b=window.pagenow.length?window.pagenow:"";window.typenow.length&&window.typenow;"edit-product"===b&&(t=!1,r("input#doaction, input#doaction2").on("click",function(o){if(t)return!0;o.preventDefault();var e,c=r(this),o=c.prev("select").val();"facebook_include"===o?(e=[],r.each(r('input[name="post[]"]:checked'),function(){e.push(parseInt(r(this).val(),10))}),r.post(facebook_for_woocommerce_products_admin.ajax_url,{action:"facebook_for_woocommerce_set_product_sync_bulk_action_prompt",security:facebook_for_woocommerce_products_admin.set_product_sync_bulk_action_prompt_nonce,toggle:o,products:e},function(o){o&&!o.success?(r("#wc-backbone-modal-dialog .modal-close").trigger("click"),new r.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:o.data})):(t=!0,c.trigger("click"))})):(t=!0,c.trigger("click"))})),"product"===b&&(e=function(o,e){e.find(".enable-if-sync-enabled").prop("disabled",!o)},c=function(o,e){o?(e.find("option[value='sync_and_show']").show(),e.prop("original")&&e.val(e.prop("original"))):(e.find("option[value='sync_and_show']").hide(),"sync_and_show"===e.val()&&e.val("sync_and_hide"))},n=function(o,e){var c=e.find("#wc_facebook_commerce_enabled"),t=c.prop("original");c.prop("checked",!!o&&t).prop("disabled",!o),c.trigger("change"),c.prop("original",t),e.find("#product-not-ready-notice, #variable-product-not-ready-notice").hide(),d()&&!s()?e.find("#variable-product-not-ready-notice").show():o||e.find("#product-not-ready-notice").show()},i=function(){return!!o()&&(!!_()&&!!u())},o=function(){return(d()?s:a)()},s=function(){var o=r(".js-variable-fb-sync-toggle");return 0===o.length?!!facebook_for_woocommerce_products_admin.is_sync_enabled_for_product:!!o.map(function(o,e){return"sync_disabled"!==r(e).val()?e:null}).length},a=function(){return"sync_disabled"!==r("#wc_facebook_sync_mode").val()},_=function(){return!!d()||l()},d=function(){var o=r("select#product-type").val();return!(!o||!o.match(/variable/))},l=function(){return!(!r("#_regular_price").val()&&!r("#fb_product_price").val())},u=function(){return p()},p=function(){return!(!r("#_manage_stock").prop("checked")||!r("#_stock").val())},r("#facebook_options #wc_facebook_commerce_enabled").on("change",function(){var o=r(this).prop("checked");o?r(".wc_facebook_commerce_fields").show():r(".wc_facebook_commerce_fields").hide(),r(".product_attributes").find(".woocommerce_attribute").length?r(".show_if_has_attributes").show():r(".show_if_has_attributes").hide(),r(this).prop("original",o)}).trigger("change"),f=r("#wc_facebook_sync_mode"),m=f.closest(".woocommerce_options_panel"),f.on("change",function(){var o="sync_disabled"!==r(this).val();e(o,m),function(o,e){e=e.find(".wc-facebook-commerce-options-group");o?e.show():e.hide()}(o,m),f.prop("original",r(this).val())}).trigger("change"),r("#_virtual").on("change",function(){c(!r(this).prop("checked"),f)}).trigger("change"),r("#woocommerce-product-data").on("change","#_regular_price, #_manage_stock, #_stock, #wc_facebook_sync_mode, #fb_product_price",function(o){setTimeout(function(){n(i(),r("#facebook_options"))},1)}),r(".woocommerce_variations").on("change",".js-variable-fb-sync-toggle",function(){e("sync_disabled"!==r(this).val(),r(this).closest(".wc-metabox-content")),n(i(),r("#facebook_options")),r(this).prop("original",r(this).val())}),r("#woocommerce-product-data").on("woocommerce_variations_loaded",function(){r(".js-variable-fb-sync-toggle").each(function(){e("sync_disabled"!==r(this).val(),r(this).closest(".wc-metabox-content")),r(this).prop("original",r(this).val())}),r(".variable_is_virtual").on("change",function(){var o=r(this).closest(".wc-metabox-content").find(".js-variable-fb-sync-toggle");c(!r(this).prop("checked"),o)}),n(i(),r("#facebook_options"))}),r("#woocommerce-product-data").on("change",".js-fb-product-image-source",function(){var o=r(this).closest(".woocommerce_options_panel, .wc-metabox-content"),e=r(this).val();o.find(".product-image-source-field").closest(".form-field").hide(),o.find(".show-if-product-image-source-"+e).closest(".form-field").show()}),r(".js-fb-product-image-source:checked:visible").trigger("change"),r("#woocommerce-product-data").on("woocommerce_variations_loaded",function(){r(".js-variable-fb-sync-toggle:visible").trigger("change"),r(".js-fb-product-image-source:checked:visible").trigger("change"),r(".variable_is_virtual:visible").trigger("change")}),r("#facebook_options").on("click","#product-not-ready-notice-open-modal",function(o){o.preventDefault(),r("#wc-backbone-modal-dialog .modal-close").trigger("click"),new r.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:{message:facebook_for_woocommerce_products_admin.product_not_ready_modal_message,buttons:facebook_for_woocommerce_products_admin.product_not_ready_modal_buttons}})}),n(i(),m),g=!1,r('form#post input[type="submit"]').on("click",function(o){if(!!r("#wc_facebook_commerce_enabled").prop("checked")&&(!!i()&&r(".wc_facebook_commerce_fields .wc-facebook-google-product-category-select").map(function(o,e){return r(e).val()?r(e).val():null}).length<2))return o.preventDefault(),alert(facebook_for_woocommerce_products_admin.i18n.missing_google_product_category_message),!1;if(g)return!0;o.preventDefault();var e=r(this),c=parseInt(r("input#post_ID").val(),10),t=[],n=r('textarea[name="tax_input[product_tag]"]').length?r('textarea[name="tax_input[product_tag]"]').val().split(","):[],a="sync_disabled"!==r("#wc_facebook_sync_mode").val(),o=s();r('#taxonomy-product_cat input[name="tax_input[product_cat][]"]:checked').each(function(){t.push(parseInt(r(this).val(),10))}),r('#taxonomy-product_tag input[name="tax_input[product_tag][]"]:checked').each(function(){n.push(parseInt(r(this).val(),10))}),0<c?r.post(facebook_for_woocommerce_products_admin.ajax_url,{action:"facebook_for_woocommerce_set_product_sync_prompt",security:facebook_for_woocommerce_products_admin.set_product_sync_prompt_nonce,sync_enabled:a?"enabled":"disabled",var_sync_enabled:o?"enabled":"disabled",product:c,categories:t,tags:n},function(o){o&&!o.success&&a?(r("#wc-backbone-modal-dialog .modal-close").trigger("click"),new r.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:o.data})):(g=!0,e.trigger("click"))}):(g=!0,e.trigger("click"))}))});
1
+ "use strict";jQuery(document).ready(function(r){var t,n,e,c,i,o,s,a,_,d,l,u,p,f,m,g,b,v,h,w,k,y,x,j,M,D,E=window.pagenow.length?window.pagenow:"";window.typenow.length&&window.typenow;"edit-product"===E&&(t=!1,r("input#doaction, input#doaction2").on("click",function(o){if(t)return!0;o.preventDefault();var e,c=r(this),o=c.prev("select").val();"facebook_include"===o?(e=[],r.each(r('input[name="post[]"]:checked'),function(){e.push(parseInt(r(this).val(),10))}),r.post(facebook_for_woocommerce_products_admin.ajax_url,{action:"facebook_for_woocommerce_set_product_sync_bulk_action_prompt",security:facebook_for_woocommerce_products_admin.set_product_sync_bulk_action_prompt_nonce,toggle:o,products:e},function(o){o&&!o.success?(closeExistingModal(),new r.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:o.data})):(t=!0,c.trigger("click"))})):(t=!0,c.trigger("click"))})),"product"===E&&(n=function(o,e){e.find(".enable-if-sync-enabled").prop("disabled",!o)},e=function(o,e){o?(e.find("option[value='sync_and_show']").show(),e.prop("original")&&e.val(e.prop("original"))):(e.find("option[value='sync_and_show']").hide(),"sync_and_show"===e.val()&&e.val("sync_and_hide"))},c=function(o,e){var c=e.find("#wc_facebook_commerce_enabled"),t=c.prop("original");c.prop("checked",!!o&&t).prop("disabled",!o),c.trigger("change"),c.prop("original",t),e.find("#product-not-ready-notice, #variable-product-not-ready-notice").hide(),d()&&!s()?e.find("#variable-product-not-ready-notice").show():o||e.find("#product-not-ready-notice").show()},i=function(){return!!o()&&(!!_()&&!!u())},o=function(){return(d()?s:a)()},s=function(){var o=r(".js-variable-fb-sync-toggle");return 0===o.length?!!facebook_for_woocommerce_products_admin.is_sync_enabled_for_product:!!o.map(function(o,e){return"sync_disabled"!==r(e).val()?e:null}).length},a=function(){return"sync_disabled"!==x.val()},_=function(){return!!d()||l()},d=function(){var o=r("select#product-type").val();return!(!o||!o.match(/variable/))},l=function(){return!(!r("#_regular_price").val()&&!r("#fb_product_price").val())},u=function(){return p()},p=function(){return!(!r("#_manage_stock").prop("checked")||!r("#_stock").val())},f=function(o){o.attr("data-original-value",o.val())},m=function(o){return-1<o.map(function(o,e){var c=r(e),e=c.val();return"sync_disabled"===e&&e!==c.attr("data-original-value")}).toArray().indexOf(!0)},g=function(o){return(x===o?r("input#post_ID"):o.closest(".woocommerce_variation").find("input[name^=variable_post_id]")).val()},b=function(o){closeExistingModal(),k=g(w=o),new r.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:{message:facebook_for_woocommerce_products_admin.product_removed_from_sync_confirm_modal_message,buttons:facebook_for_woocommerce_products_admin.product_removed_from_sync_confirm_modal_buttons}})},v=function(){r(facebook_for_woocommerce_products_admin.product_removed_from_sync_field_id).val(y.join(","))},h=function(e){y=y.filter(function(o){return o!==e}),v()},k=w=null,y=[],r(document.body).on("click","button.button-product-removed-from-sync-delete",function(){k&&(closeExistingModal(),y.push(k),v())}).on("click","button.button-product-removed-from-sync-cancel",function(){var o;closeExistingModal(),w&&((o=w).val(o.attr("data-original-value")),w=null),v()}),r("#facebook_options #wc_facebook_commerce_enabled").on("change",function(){var o=r(this).prop("checked");o?r(".wc_facebook_commerce_fields").show():r(".wc_facebook_commerce_fields").hide(),r(".product_attributes").find(".woocommerce_attribute").length?r(".show_if_has_attributes").show():r(".show_if_has_attributes").hide(),r(this).prop("original",o)}).trigger("change"),x=r("#wc_facebook_sync_mode"),j=x.closest(".woocommerce_options_panel"),f(x),x.on("change",function(){var o,e,c="sync_disabled"!==x.val();n(c,j),o=c,e=(e=j).find(".wc-facebook-commerce-options-group"),o?e.show():e.hide(),c&&h(g(x)),x.prop("original",x.val()),m(x)&&b(x)}).trigger("change"),r("#_virtual").on("change",function(){e(!r(this).prop("checked"),x)}).trigger("change"),(M=r("#woocommerce-product-data")).on("change","#_regular_price, #_manage_stock, #_stock, #wc_facebook_sync_mode, #fb_product_price",function(o){setTimeout(function(){c(i(),r("#facebook_options"))},1)}),r(".woocommerce_variations").on("change",".js-variable-fb-sync-toggle",function(){var o=r(this),e="sync_disabled"!==o.val();n(e,o.closest(".wc-metabox-content")),c(i(),r("#facebook_options")),e&&h(g(o)),o.prop("original",o.val()),m(o)&&b(o)}),M.on("woocommerce_variations_loaded",function(){M.find(".js-variable-fb-sync-toggle").each(function(o,e){e=r(e);n("sync_disabled"!==e.val(),e.closest(".wc-metabox-content")),e.prop("original",e.val()),f(e)}),r(".variable_is_virtual").on("change",function(){var o=r(this).closest(".wc-metabox-content").find(".js-variable-fb-sync-toggle");e(!r(this).prop("checked"),o)}),c(i(),r("#facebook_options"))}),M.on("change",".js-fb-product-image-source",function(){var o=r(this).closest(".woocommerce_options_panel, .wc-metabox-content"),e=r(this).val();o.find(".product-image-source-field").closest(".form-field").hide(),o.find(".show-if-product-image-source-"+e).closest(".form-field").show()}),r(".js-fb-product-image-source:checked:visible").trigger("change"),M.on("woocommerce_variations_loaded",function(){r(".js-variable-fb-sync-toggle:visible").trigger("change"),r(".js-fb-product-image-source:checked:visible").trigger("change"),r(".variable_is_virtual:visible").trigger("change")}),r("#facebook_options").on("click","#product-not-ready-notice-open-modal",function(o){o.preventDefault(),closeExistingModal(),new r.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:{message:facebook_for_woocommerce_products_admin.product_not_ready_modal_message,buttons:facebook_for_woocommerce_products_admin.product_not_ready_modal_buttons}})}),c(i(),j),D=!1,r('form#post input[type="submit"]').on("click",function(o){if(!!r("#wc_facebook_commerce_enabled").prop("checked")&&(!!i()&&r(".wc_facebook_commerce_fields .wc-facebook-google-product-category-select").map(function(o,e){return r(e).val()?r(e).val():null}).length<2))return o.preventDefault(),alert(facebook_for_woocommerce_products_admin.i18n.missing_google_product_category_message),!1;if(D)return!0;o.preventDefault();var e=r(this),c=parseInt(r("input#post_ID").val(),10),t=[],n=r('textarea[name="tax_input[product_tag]"]').length?r('textarea[name="tax_input[product_tag]"]').val().split(","):[],a="sync_disabled"!==x.val(),o=s();r('#taxonomy-product_cat input[name="tax_input[product_cat][]"]:checked').each(function(){t.push(parseInt(r(this).val(),10))}),r('#taxonomy-product_tag input[name="tax_input[product_tag][]"]:checked').each(function(){n.push(parseInt(r(this).val(),10))}),0<c?r.post(facebook_for_woocommerce_products_admin.ajax_url,{action:"facebook_for_woocommerce_set_product_sync_prompt",security:facebook_for_woocommerce_products_admin.set_product_sync_prompt_nonce,sync_enabled:a?"enabled":"disabled",var_sync_enabled:o?"enabled":"disabled",product:c,categories:t,tags:n},function(o){o&&!o.success&&a?(closeExistingModal(),new r.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:o.data})):(D=!0,e.trigger("click"))}):(D=!0,e.trigger("click"))}))});
assets/js/admin/facebook-for-woocommerce-products-admin.min.old.min.js CHANGED
@@ -1 +1 @@
1
- "use strict";jQuery(document).ready(function(r){var t,c,e,a,i,o,n,s,d,_,l,u,p,f,m,g=window.pagenow.length?window.pagenow:"";window.typenow.length&&window.typenow,"edit-product"===g&&(t=!1,r("input#doaction, input#doaction2").on("click",function(o){if(t)return!0;o.preventDefault();var e,c=r(this),o=c.prev("select").val();"facebook_include"===o?(e=[],r.each(r('input[name="post[]"]:checked'),function(){e.push(parseInt(r(this).val(),10))}),r.post(facebook_for_woocommerce_products_admin.ajax_url,{action:"facebook_for_woocommerce_set_product_sync_bulk_action_prompt",security:facebook_for_woocommerce_products_admin.set_product_sync_bulk_action_prompt_nonce,toggle:o,products:e},function(o){o&&!o.success?(r("#wc-backbone-modal-dialog .modal-close").trigger("click"),new r.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:o.data})):(t=!0,c.trigger("click"))})):(t=!0,c.trigger("click"))})),"product"===g&&(c=function(o,e){e.find(".enable-if-sync-enabled").prop("disabled",!o)},e=function(o,e){o?(e.find("option[value='sync_and_show']").show(),e.prop("original")&&e.val(e.prop("original"))):(e.find("option[value='sync_and_show']").hide(),"sync_and_show"===e.val()&&e.val("sync_and_hide"))},a=function(o,e){var c=e.find("#wc_facebook_commerce_enabled"),t=c.prop("original");c.prop("checked",!!o&&t).prop("disabled",!o),c.trigger("change"),c.prop("original",t),e.find("#product-not-ready-notice, #variable-product-not-ready-notice").hide(),r("select#product-type").val().match(/variable/)&&!n()?e.find("#variable-product-not-ready-notice").show():o||e.find("#product-not-ready-notice").show()},i=function(){return!!o()&&!!d()&&!!l()},o=function(){return(r("select#product-type").val().match(/variable/)?n:s)()},n=function(){var o=r(".js-variable-fb-sync-toggle");return 0===o.length?!!facebook_for_woocommerce_products_admin.is_sync_enabled_for_product:!!o.map(function(o,e){return"sync_disabled"!==r(e).val()?e:null}).length},s=function(){return"sync_disabled"!==r("#wc_facebook_sync_mode").val()},d=function(){return!!r("select#product-type").val().match(/variable/)||_()},_=function(){return r("#_regular_price").val().length||r("#fb_product_price").val().length},l=function(){return u()},u=function(){return r("#_manage_stock").prop("checked")&&r("#_stock").val().length},r("#facebook_options #wc_facebook_commerce_enabled").on("change",function(){var o=r(this).prop("checked");o?r(".wc_facebook_commerce_fields").show():r(".wc_facebook_commerce_fields").hide(),r(".product_attributes").find(".woocommerce_attribute").length?r(".show_if_has_attributes").show():r(".show_if_has_attributes").hide(),r(this).prop("original",o)}).trigger("change"),p=r("#wc_facebook_sync_mode"),f=p.closest(".woocommerce_options_panel"),p.on("change",function(){var o,e="sync_disabled"!==r(this).val();c(e,f),o=e,e=f.find(".wc-facebook-commerce-options-group"),o?e.show():e.hide(),p.prop("original",r(this).val())}).trigger("change"),r("#_virtual").on("change",function(){e(!r(this).prop("checked"),p)}).trigger("change"),r("#woocommerce-product-data").on("change","#_regular_price, #_manage_stock, #_stock, #wc_facebook_sync_mode, #fb_product_price",function(o){setTimeout(function(){a(i(),r("#facebook_options"))},1)}),r(".woocommerce_variations").on("change",".js-variable-fb-sync-toggle",function(){c("sync_disabled"!==r(this).val(),r(this).closest(".wc-metabox-content")),a(i(),r("#facebook_options")),r(this).prop("original",r(this).val())}),r("#woocommerce-product-data").on("woocommerce_variations_loaded",function(){r(".js-variable-fb-sync-toggle").each(function(){c("sync_disabled"!==r(this).val(),r(this).closest(".wc-metabox-content")),r(this).prop("original",r(this).val())}),r(".variable_is_virtual").on("change",function(){var o=r(this).closest(".wc-metabox-content").find(".js-variable-fb-sync-toggle");e(!r(this).prop("checked"),o)}),a(i(),r("#facebook_options"))}),r("#woocommerce-product-data").on("change",".js-fb-product-image-source",function(){var o=r(this).closest(".woocommerce_options_panel, .wc-metabox-content"),e=r(this).val();o.find(".product-image-source-field").closest(".form-field").hide(),o.find(".show-if-product-image-source-"+e).closest(".form-field").show()}),r(".js-fb-product-image-source:checked:visible").trigger("change"),r("#woocommerce-product-data").on("woocommerce_variations_loaded",function(){r(".js-variable-fb-sync-toggle:visible").trigger("change"),r(".js-fb-product-image-source:checked:visible").trigger("change"),r(".variable_is_virtual:visible").trigger("change")}),r("#facebook_options").on("click","#product-not-ready-notice-open-modal",function(o){o.preventDefault(),r("#wc-backbone-modal-dialog .modal-close").trigger("click"),new r.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:{message:facebook_for_woocommerce_products_admin.product_not_ready_modal_message,buttons:facebook_for_woocommerce_products_admin.product_not_ready_modal_buttons}})}),a(i(),f),m=!1,r('form#post input[type="submit"]').on("click",function(o){if(r("#wc_facebook_commerce_enabled").prop("checked")&&i()&&r(".wc_facebook_commerce_fields .wc-facebook-google-product-category-select").map(function(o,e){return r(e).val()?r(e).val():null}).length<2)return o.preventDefault(),alert(facebook_for_woocommerce_products_admin.i18n.missing_google_product_category_message),!1;if(m)return!0;o.preventDefault();var e=r(this),c=parseInt(r("input#post_ID").val(),10),t=[],a=r('textarea[name="tax_input[product_tag]"]').length?r('textarea[name="tax_input[product_tag]"]').val().split(","):[],n="sync_disabled"!==r("#wc_facebook_sync_mode").val(),o="sync_disabled"!==r(".js-variable-fb-sync-toggle").val();r('#taxonomy-product_cat input[name="tax_input[product_cat][]"]:checked').each(function(){t.push(parseInt(r(this).val(),10))}),r('#taxonomy-product_tag input[name="tax_input[product_tag][]"]:checked').each(function(){a.push(parseInt(r(this).val(),10))}),0<c?r.post(facebook_for_woocommerce_products_admin.ajax_url,{action:"facebook_for_woocommerce_set_product_sync_prompt",security:facebook_for_woocommerce_products_admin.set_product_sync_prompt_nonce,sync_enabled:n?"enabled":"disabled",var_sync_enabled:o?"enabled":"disabled",product:c,categories:t,tags:a},function(o){o&&!o.success&&n?(r("#wc-backbone-modal-dialog .modal-close").trigger("click"),new r.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:o.data})):(m=!0,e.trigger("click"))}):(m=!0,e.trigger("click"))}))});
1
+ "use strict";jQuery(document).ready(function(r){var t,c,e,a,i,o,n,s,d,_,l,u,p,f,m,g=window.pagenow.length?window.pagenow:"";window.typenow.length&&window.typenow,"edit-product"===g&&(t=!1,r("input#doaction, input#doaction2").on("click",function(o){if(t)return!0;o.preventDefault();var e,c=r(this),o=c.prev("select").val();"facebook_include"===o?(e=[],r.each(r('input[name="post[]"]:checked'),function(){e.push(parseInt(r(this).val(),10))}),r.post(facebook_for_woocommerce_products_admin.ajax_url,{action:"facebook_for_woocommerce_set_product_sync_bulk_action_prompt",security:facebook_for_woocommerce_products_admin.set_product_sync_bulk_action_prompt_nonce,toggle:o,products:e},function(o){o&&!o.success?(r("#wc-backbone-modal-dialog .modal-close").trigger("click"),new r.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:o.data})):(t=!0,c.trigger("click"))})):(t=!0,c.trigger("click"))})),"product"===g&&(c=function(o,e){e.find(".enable-if-sync-enabled").prop("disabled",!o)},e=function(o,e){o?(e.find("option[value='sync_and_show']").show(),e.prop("original")&&e.val(e.prop("original"))):(e.find("option[value='sync_and_show']").hide(),"sync_and_show"===e.val()&&e.val("sync_and_hide"))},a=function(o,e){var c,t=(c=e.find("#wc_facebook_commerce_enabled")).prop("original");c.prop("checked",!!o&&t).prop("disabled",!o),c.trigger("change"),c.prop("original",t),e.find("#product-not-ready-notice, #variable-product-not-ready-notice").hide(),r("select#product-type").val().match(/variable/)&&!n()?e.find("#variable-product-not-ready-notice").show():o||e.find("#product-not-ready-notice").show()},i=function(){return!!o()&&!!d()&&!!l()},o=function(){return(r("select#product-type").val().match(/variable/)?n:s)()},n=function(){var o=r(".js-variable-fb-sync-toggle");return 0===o.length?!!facebook_for_woocommerce_products_admin.is_sync_enabled_for_product:!!o.map(function(o,e){return"sync_disabled"!==r(e).val()?e:null}).length},s=function(){return"sync_disabled"!==r("#wc_facebook_sync_mode").val()},d=function(){return!!r("select#product-type").val().match(/variable/)||_()},_=function(){return r("#_regular_price").val().length||r("#fb_product_price").val().length},l=function(){return u()},u=function(){return r("#_manage_stock").prop("checked")&&r("#_stock").val().length},r("#facebook_options #wc_facebook_commerce_enabled").on("change",function(){var o=r(this).prop("checked");o?r(".wc_facebook_commerce_fields").show():r(".wc_facebook_commerce_fields").hide(),r(".product_attributes").find(".woocommerce_attribute").length?r(".show_if_has_attributes").show():r(".show_if_has_attributes").hide(),r(this).prop("original",o)}).trigger("change"),p=r("#wc_facebook_sync_mode"),f=p.closest(".woocommerce_options_panel"),p.on("change",function(){var o,e="sync_disabled"!==r(this).val();c(e,f),o=e,e=f.find(".wc-facebook-commerce-options-group"),o?e.show():e.hide(),p.prop("original",r(this).val())}).trigger("change"),r("#_virtual").on("change",function(){e(!r(this).prop("checked"),p)}).trigger("change"),r("#woocommerce-product-data").on("change","#_regular_price, #_manage_stock, #_stock, #wc_facebook_sync_mode, #fb_product_price",function(o){setTimeout(function(){a(i(),r("#facebook_options"))},1)}),r(".woocommerce_variations").on("change",".js-variable-fb-sync-toggle",function(){c("sync_disabled"!==r(this).val(),r(this).closest(".wc-metabox-content")),a(i(),r("#facebook_options")),r(this).prop("original",r(this).val())}),r("#woocommerce-product-data").on("woocommerce_variations_loaded",function(){r(".js-variable-fb-sync-toggle").each(function(){c("sync_disabled"!==r(this).val(),r(this).closest(".wc-metabox-content")),r(this).prop("original",r(this).val())}),r(".variable_is_virtual").on("change",function(){var o=r(this).closest(".wc-metabox-content").find(".js-variable-fb-sync-toggle");e(!r(this).prop("checked"),o)}),a(i(),r("#facebook_options"))}),r("#woocommerce-product-data").on("change",".js-fb-product-image-source",function(){var o=r(this).closest(".woocommerce_options_panel, .wc-metabox-content"),e=r(this).val();o.find(".product-image-source-field").closest(".form-field").hide(),o.find(".show-if-product-image-source-"+e).closest(".form-field").show()}),r(".js-fb-product-image-source:checked:visible").trigger("change"),r("#woocommerce-product-data").on("woocommerce_variations_loaded",function(){r(".js-variable-fb-sync-toggle:visible").trigger("change"),r(".js-fb-product-image-source:checked:visible").trigger("change"),r(".variable_is_virtual:visible").trigger("change")}),r("#facebook_options").on("click","#product-not-ready-notice-open-modal",function(o){o.preventDefault(),r("#wc-backbone-modal-dialog .modal-close").trigger("click"),new r.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:{message:facebook_for_woocommerce_products_admin.product_not_ready_modal_message,buttons:facebook_for_woocommerce_products_admin.product_not_ready_modal_buttons}})}),a(i(),f),m=!1,r('form#post input[type="submit"]').on("click",function(o){if(r("#wc_facebook_commerce_enabled").prop("checked")&&i()&&r(".wc_facebook_commerce_fields .wc-facebook-google-product-category-select").map(function(o,e){return r(e).val()?r(e).val():null}).length<2)return o.preventDefault(),alert(facebook_for_woocommerce_products_admin.i18n.missing_google_product_category_message),!1;if(m)return!0;o.preventDefault();var e=r(this),c=parseInt(r("input#post_ID").val(),10),t=[],a=r('textarea[name="tax_input[product_tag]"]').length?r('textarea[name="tax_input[product_tag]"]').val().split(","):[],n="sync_disabled"!==r("#wc_facebook_sync_mode").val(),o="sync_disabled"!==r(".js-variable-fb-sync-toggle").val();r('#taxonomy-product_cat input[name="tax_input[product_cat][]"]:checked').each(function(){t.push(parseInt(r(this).val(),10))}),r('#taxonomy-product_tag input[name="tax_input[product_tag][]"]:checked').each(function(){a.push(parseInt(r(this).val(),10))}),0<c?r.post(facebook_for_woocommerce_products_admin.ajax_url,{action:"facebook_for_woocommerce_set_product_sync_prompt",security:facebook_for_woocommerce_products_admin.set_product_sync_prompt_nonce,sync_enabled:n?"enabled":"disabled",var_sync_enabled:o?"enabled":"disabled",product:c,categories:t,tags:a},function(o){o&&!o.success&&n?(r("#wc-backbone-modal-dialog .modal-close").trigger("click"),new r.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:o.data})):(m=!0,e.trigger("click"))}):(m=!0,e.trigger("click"))}))});
assets/js/admin/facebook-for-woocommerce-settings-sync.min.js CHANGED
@@ -1 +1 @@
1
- "use strict";jQuery(document).ready(function(s){function c(e){s(".product-sync-field").each(function(){var o=s(this);s(this).hasClass("wc-enhanced-select")&&(o=s(this).next("span.select2-container")),e?o.css("pointer-events","all").css("opacity","1.0"):o.css("pointer-events","none").css("opacity","0.4")})}s(".woocommerce-help-tip").tipTip({attribute:"data-tip",fadeIn:50,fadeOut:50,delay:200}),s("form.wc-facebook-settings").hasClass("disconnected")&&c(!1),s("input#wc_facebook_enable_product_sync").on("change",function(o){s("form.wc-facebook-settings").hasClass("disconnected")?s(this).css("pointer-events","none").css("opacity","0.4"):c(s(this).is(":checked"))}).trigger("change");var t=!1;function e(o){n(0<arguments.length&&void 0!==o?o:null),window.syncStatusInterval||(window.syncStatusInterval=setInterval(r,1e4))}function n(o){var e=0<arguments.length&&void 0!==o?o:null;c(!1),s('input#wc_facebook_enable_product_sync, input[name="save_product_sync_settings"]').css("pointer-events","none").css("opacity","0.4");o=facebook_for_woocommerce_settings_sync.i18n.sync_in_progress;e&&(o=(o+=1<e?facebook_for_woocommerce_settings_sync.i18n.sync_remaining_items_plural:facebook_for_woocommerce_settings_sync.i18n.sync_remaining_items_singular).replace("{count}",e)),s("#sync_progress").show().html(o).css("color","inherit"),facebook_for_woocommerce_settings_sync.sync_in_progress=!0}function _(o){o=0<arguments.length&&void 0!==o?o:"";facebook_for_woocommerce_settings_sync.sync_in_progress=!1,clearInterval(window.syncStatusInterval),c(!(window.syncStatusInterval=null)),s('input#wc_facebook_enable_product_sync, input[name="save_product_sync_settings"]').css("pointer-events","all").css("opacity","1"),o?s("#sync_progress").show().html(o).css("color","#DC3232"):s("#sync_progress").hide()}function r(){facebook_for_woocommerce_settings_sync.sync_in_progress&&s.post(facebook_for_woocommerce_settings_sync.ajax_url,{action:"wc_facebook_get_sync_status",nonce:facebook_for_woocommerce_settings_sync.sync_status_nonce},function(o){console.log(o),o.success&&(0<o.data?e(o.data):_())})}s('input[name="save_product_sync_settings"]').on("click",function(o){if(t)return!0;o.preventDefault();var e,c,n=s(this),o=(e=s("#wc_facebook_excluded_product_category_ids").val(),c=[],window.facebook_for_woocommerce_settings_sync&&window.facebook_for_woocommerce_settings_sync.excluded_category_ids&&(c=window.facebook_for_woocommerce_settings_sync.excluded_category_ids),s(e).not(c).get()),c=(e=s("#wc_facebook_excluded_product_tag_ids").val(),c=[],window.facebook_for_woocommerce_settings_sync&&window.facebook_for_woocommerce_settings_sync.excluded_tag_ids&&(c=window.facebook_for_woocommerce_settings_sync.excluded_tag_ids),s(e).not(c).get());0<o.length||0<c.length?s.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:o,tags:c},function(o){o&&!o.success?(s("#wc-backbone-modal-dialog .modal-close").trigger("click"),new s.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:o.data}),s(".facebook-for-woocommerce-confirm-settings-change").on("click",function(){blockModal(),t=!0,n.trigger("click")})):(t=!0,n.trigger("click"))}):(t=!0,n.trigger("click"))}),facebook_for_woocommerce_settings_sync.sync_in_progress&&e(),s("#woocommerce-facebook-settings-sync-products").click(function(o){var c;o.preventDefault(),confirm(facebook_for_woocommerce_settings_sync.i18n.confirm_sync)&&(n(),c=Date.now(),s.post(facebook_for_woocommerce_settings_sync.ajax_url,{action:"wc_facebook_sync_products",nonce:facebook_for_woocommerce_settings_sync.sync_products_nonce},function(o){var e;console.log(o),o.success?setTimeout(r,Math.max(0,1e4-(Date.now()-c))):(e=facebook_for_woocommerce_settings_sync.i18n.general_error,o.data&&0<o.data.length&&(e=o.data),_(e))}).fail(function(){_(facebook_for_woocommerce_settings_sync.i18n.general_error)}))})});
1
+ "use strict";jQuery(document).ready(function(s){function c(e){s(".product-sync-field").each(function(){var o=s(this);s(this).hasClass("wc-enhanced-select")&&(o=s(this).next("span.select2-container")),e?o.css("pointer-events","all").css("opacity","1.0"):o.css("pointer-events","none").css("opacity","0.4")})}s(".woocommerce-help-tip").tipTip({attribute:"data-tip",fadeIn:50,fadeOut:50,delay:200}),s("form.wc-facebook-settings").hasClass("disconnected")&&c(!1),s("input#wc_facebook_enable_product_sync").on("change",function(o){s("form.wc-facebook-settings").hasClass("disconnected")?s(this).css("pointer-events","none").css("opacity","0.4"):c(s(this).is(":checked"))}).trigger("change");var t=!1;function e(o){n(0<arguments.length&&void 0!==o?o:null),window.syncStatusInterval||(window.syncStatusInterval=setInterval(r,1e4))}function n(o){var e=0<arguments.length&&void 0!==o?o:null;c(!1),s('input#wc_facebook_enable_product_sync, input[name="save_product_sync_settings"]').css("pointer-events","none").css("opacity","0.4");o=facebook_for_woocommerce_settings_sync.i18n.sync_in_progress;e&&(o=(o+=1<e?facebook_for_woocommerce_settings_sync.i18n.sync_remaining_items_plural:facebook_for_woocommerce_settings_sync.i18n.sync_remaining_items_singular).replace("{count}",e)),s("#sync_progress").show().html(o).css("color","inherit"),facebook_for_woocommerce_settings_sync.sync_in_progress=!0}function _(o){o=0<arguments.length&&void 0!==o?o:"";facebook_for_woocommerce_settings_sync.sync_in_progress=!1,clearInterval(window.syncStatusInterval),c(!(window.syncStatusInterval=null)),s('input#wc_facebook_enable_product_sync, input[name="save_product_sync_settings"]').css("pointer-events","all").css("opacity","1"),o?s("#sync_progress").show().html(o).css("color","#DC3232"):s("#sync_progress").hide()}function r(){facebook_for_woocommerce_settings_sync.sync_in_progress&&s.post(facebook_for_woocommerce_settings_sync.ajax_url,{action:"wc_facebook_get_sync_status",nonce:facebook_for_woocommerce_settings_sync.sync_status_nonce},function(o){console.log(o),o.success&&(0<o.data?e(o.data):_())})}s('input[name="save_product_sync_settings"]').on("click",function(o){if(t)return!0;o.preventDefault();var e,c,n=s(this),o=(e=s("#wc_facebook_excluded_product_category_ids").val(),c=[],window.facebook_for_woocommerce_settings_sync&&window.facebook_for_woocommerce_settings_sync.excluded_category_ids&&(c=window.facebook_for_woocommerce_settings_sync.excluded_category_ids),s(e).not(c).get()),c=(e=s("#wc_facebook_excluded_product_tag_ids").val(),c=[],window.facebook_for_woocommerce_settings_sync&&window.facebook_for_woocommerce_settings_sync.excluded_tag_ids&&(c=window.facebook_for_woocommerce_settings_sync.excluded_tag_ids),s(e).not(c).get());0<o.length||0<c.length?s.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:o,tags:c},function(o){o&&!o.success?(s("#wc-backbone-modal-dialog .modal-close").trigger("click"),new s.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:o.data}),s(".facebook-for-woocommerce-confirm-settings-change").on("click",function(){blockModal(),t=!0,n.trigger("click")})):(t=!0,n.trigger("click"))}):(t=!0,n.trigger("click"))}),facebook_for_woocommerce_settings_sync.sync_in_progress&&e(),s("#woocommerce-facebook-settings-sync-products").click(function(o){var c;o.preventDefault(),confirm(facebook_for_woocommerce_settings_sync.i18n.confirm_sync)&&(n(),c=Date.now(),s.post(facebook_for_woocommerce_settings_sync.ajax_url,{action:"wc_facebook_sync_products",nonce:facebook_for_woocommerce_settings_sync.sync_products_nonce},function(o){var e;console.log(o),o.success?setTimeout(r,Math.max(0,1e4-(Date.now()-c))):(e=facebook_for_woocommerce_settings_sync.i18n.general_error,_(e=o.data&&0<o.data.length?o.data:e))}).fail(function(){_(facebook_for_woocommerce_settings_sync.i18n.general_error)}))})});
assets/js/admin/orders.min.js CHANGED
@@ -1 +1 @@
1
- "use strict";jQuery(document).ready(function(a){var c=Boolean(wc_facebook_commerce_orders.is_commerce_order),o={restrict_order_statuses:function(e){e.find("option").each(function(e,o){-1===wc_facebook_commerce_orders.allowed_commerce_statuses.indexOf(o.value)&&o.remove()})},toggle_created_date_fields_status:function(e){o.toggle_field(a("#order_data").find("input[name*=order_date]"),e)},disable_order_status_field:function(e){o.toggle_field(e,!1)},toggle_order_customer_field:function(e){a("#order_data").find(".form-field.wc-customer-user").toggleClass("hidden",e)},toggle_billing_and_shipping_fields:function(e){a("#order_data").find("a.edit_address").toggleClass("hidden",e)},disable_pending_order_related_fields:function(e){o.toggle_created_date_fields_status(!1),o.disable_order_status_field(e),o.toggle_order_customer_field(!0),o.toggle_billing_and_shipping_fields(!0)},maybe_disable_refunds:function(){"completed"!==wc_facebook_commerce_orders.order_status&&a(".wc-order-bulk-actions .refund-items").hide()},toggle_field:function(e,o){e.hasClass("wc-enhanced-select")&&(e=e.next("span.select2-container")),o?e.css("pointer-events","all").css("opacity","1.0"):e.css("pointer-events","none").css("opacity","0.4")}},n=a('form[id="post"]'),r=a("#order_status"),t=r.val(),e=wc_facebook_commerce_orders.shipment_tracking,_="",d="",s="",i="";function l(e){unBlockModal(),a(".facebook-for-woocommerce-modal .wc-backbone-modal-content article").html("<p>"+e+"</p>"),a(".facebook-for-woocommerce-modal .wc-backbone-modal-content footer").remove()}function f(e,o,c){var r=0<arguments.length&&void 0!==e&&e,o=1<arguments.length&&void 0!==o?o:null,c=2<arguments.length&&void 0!==c?c:null;o.length?(r&&blockModal(),n.find("button[type=submit].save_order").prop("disabled",!0).append('<span class="spinner is-active"></span>'),a.post(ajaxurl,{action:wc_facebook_commerce_orders.complete_order_action,order_id:a("#post_ID").val(),tracking_number:o,carrier_code:c,nonce:wc_facebook_commerce_orders.complete_order_nonce},function(e){r&&unBlockModal(),e&&e.success?n.data("allow-submit",!0).trigger("submit"):(e=e&&e.data?e.data:wc_facebook_commerce_orders.i18n.unknown_error,alert(e))}).fail(function(){l(wc_facebook_commerce_orders.i18n.unknown_error)}).always(function(){n.find("button[type=submit].save_order").prop("disabled",!1).find("span.spinner").remove()})):alert(wc_facebook_commerce_orders.i18n.missing_tracking_number_error)}function m(){var e=a("#refund_reason"),o=a("#wc_facebook_refund_reason").clone().css("width",e.css("width")),c=e.closest("tr"),e=c.clone();c.find("td.total").css("width","16em").end().find("#refund_reason").replaceWith(o.show()).end().find('label[for="refund_reason"]').attr("for","wc_facebook_refund_reason"),c.after(e),u(c,"wc_facebook_refund_reason",wc_facebook_commerce_orders.i18n.refund_reason_label,wc_facebook_commerce_orders.i18n.refund_reason_tooltip),u(e,"refund_reason",wc_facebook_commerce_orders.i18n.refund_description_label,wc_facebook_commerce_orders.i18n.refund_description_tooltip)}function u(e,o,c,r){e=e.find('label[for="'+o+'"]'),o=e.find(".woocommerce-help-tip").clone();e.text(c),r&&o.length&&(e.prepend(o),o.attr("data-tip",r).tipTip({attribute:"data-tip",fadeIn:50,fadeOut:50,delay:200}))}Array.isArray(e)&&e[0]&&(_=e[0].tracking_number,d=e[0].carrier_code),c&&(o.restrict_order_statuses(r),"pending"===wc_facebook_commerce_orders.order_status&&o.disable_pending_order_related_fields(r),"cancelled"===wc_facebook_commerce_orders.order_status&&o.disable_order_status_field(r),o.maybe_disable_refunds()),c&&(m(),function(){if(void 0===window.MutationObserver)return;var e=document.querySelector("#woocommerce-order-items .inside");if(!e)return;new MutationObserver(function(e){e.forEach(function(e){Array.prototype.forEach.call(e.addedNodes,function(e){a(e).is(".wc-order-refund-items")&&m()})})}).observe(e,{childList:!0})}()),n.on("submit",function(e){return!a("#post").data("skip-cancel-modal")&&"wc-cancelled"!==t&&(c&&"wc-cancelled"===r.val())?(e.preventDefault(),a("#wc-backbone-modal-dialog .modal-close").trigger("click"),new a.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:{message:wc_facebook_commerce_orders.cancel_modal_message,buttons:wc_facebook_commerce_orders.cancel_modal_buttons}}),a(".facebook-for-woocommerce-modal #btn-ok").off("click.facebook_for_commerce").on("click.facebook_for_commerce",function(e){e.preventDefault(),e.stopPropagation(),blockModal(),a.post(ajaxurl,{action:wc_facebook_commerce_orders.cancel_order_action,order_id:a("#post_ID").val(),reason_code:a('.facebook-for-woocommerce-modal [name="wc_facebook_cancel_reason"]').val(),security:wc_facebook_commerce_orders.cancel_order_nonce},function(e){e&&e.success?a("#post").data("skip-cancel-modal",!0).trigger("submit"):l(e&&e.data?e.data:wc_facebook_commerce_orders.i18n.unknown_error)}).fail(function(){l(wc_facebook_commerce_orders.i18n.unknown_error)})}),!1):void(c&&!n.data("allow-submit")&&("wc-refunded"===(o=r.val())&&t!==o&&(e.preventDefault(),a("#wc-backbone-modal-dialog .modal-close").trigger("click"),new a.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:{message:wc_facebook_commerce_orders.refund_modal_message,buttons:wc_facebook_commerce_orders.refund_modal_buttons}}),a(document.body).off("wc_backbone_modal_response.facebook_for_commerce").on("wc_backbone_modal_response.facebook_for_commerce",function(){a("#refund_reason").val(a("#wc_facebook_refund_reason_modal").val()),n.data("allow-submit",!0).submit()})),"wc-completed"===o&&(e.preventDefault(),_||d?f(!1,_,d):(a("#wc-backbone-modal-dialog .modal-close").trigger("click"),(i||s)&&a(document.body).off("wc_backbone_modal_loaded").on("wc_backbone_modal_loaded",function(){i&&a("#wc_facebook_carrier").val(i),s&&a("#wc_facebook_tracking_number").val(s)}),new a.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:{message:wc_facebook_commerce_orders.complete_modal_message,buttons:wc_facebook_commerce_orders.complete_modal_buttons}}),a(".facebook-for-woocommerce-modal #btn-ok").off("click.facebook_for_commerce").on("click.facebook_for_commerce",function(e){e.preventDefault(),e.stopPropagation(),i=a("#wc_facebook_carrier").val(),f(!0,s=a("#wc_facebook_tracking_number").val(),i)})))));var o})});
1
+ "use strict";jQuery(document).ready(function(a){var e,c=Boolean(wc_facebook_commerce_orders.is_commerce_order),o={restrict_order_statuses:function(e){e.find("option").each(function(e,o){-1===wc_facebook_commerce_orders.allowed_commerce_statuses.indexOf(o.value)&&o.remove()})},toggle_created_date_fields_status:function(e){o.toggle_field(a("#order_data").find("input[name*=order_date]"),e)},disable_order_status_field:function(e){o.toggle_field(e,!1)},toggle_order_customer_field:function(e){a("#order_data").find(".form-field.wc-customer-user").toggleClass("hidden",e)},toggle_billing_and_shipping_fields:function(e){a("#order_data").find("a.edit_address").toggleClass("hidden",e)},disable_pending_order_related_fields:function(e){o.toggle_created_date_fields_status(!1),o.disable_order_status_field(e),o.toggle_order_customer_field(!0),o.toggle_billing_and_shipping_fields(!0)},maybe_disable_refunds:function(){"completed"!==wc_facebook_commerce_orders.order_status&&a(".wc-order-bulk-actions .refund-items").hide()},toggle_field:function(e,o){e.hasClass("wc-enhanced-select")&&(e=e.next("span.select2-container")),o?e.css("pointer-events","all").css("opacity","1.0"):e.css("pointer-events","none").css("opacity","0.4")}},n=a('form[id="post"]'),r=a("#order_status"),t=r.val(),_=wc_facebook_commerce_orders.shipment_tracking,d="",s="",i="",l="";function m(e){unBlockModal(),a(".facebook-for-woocommerce-modal .wc-backbone-modal-content article").html("<p>"+e+"</p>"),a(".facebook-for-woocommerce-modal .wc-backbone-modal-content footer").remove()}function f(e,o,c){var r=0<arguments.length&&void 0!==e&&e,o=1<arguments.length&&void 0!==o?o:null,c=2<arguments.length&&void 0!==c?c:null;o.length?(r&&blockModal(),n.find("button[type=submit].save_order").prop("disabled",!0).append('<span class="spinner is-active"></span>'),a.post(ajaxurl,{action:wc_facebook_commerce_orders.complete_order_action,order_id:a("#post_ID").val(),tracking_number:o,carrier_code:c,nonce:wc_facebook_commerce_orders.complete_order_nonce},function(e){r&&unBlockModal(),e&&e.success?n.data("allow-submit",!0).trigger("submit"):(e=e&&e.data?e.data:wc_facebook_commerce_orders.i18n.unknown_error,alert(e))}).fail(function(){m(wc_facebook_commerce_orders.i18n.unknown_error)}).always(function(){n.find("button[type=submit].save_order").prop("disabled",!1).find("span.spinner").remove()})):alert(wc_facebook_commerce_orders.i18n.missing_tracking_number_error)}function b(){var e=a("#refund_reason"),o=a("#wc_facebook_refund_reason").clone().css("width",e.css("width")),c=e.closest("tr"),e=c.clone();c.find("td.total").css("width","16em").end().find("#refund_reason").replaceWith(o.show()).end().find('label[for="refund_reason"]').attr("for","wc_facebook_refund_reason"),c.after(e),u(c,"wc_facebook_refund_reason",wc_facebook_commerce_orders.i18n.refund_reason_label,wc_facebook_commerce_orders.i18n.refund_reason_tooltip),u(e,"refund_reason",wc_facebook_commerce_orders.i18n.refund_description_label,wc_facebook_commerce_orders.i18n.refund_description_tooltip)}function u(e,o,c,r){e=e.find('label[for="'+o+'"]'),o=e.find(".woocommerce-help-tip").clone();e.text(c),r&&o.length&&(e.prepend(o),o.attr("data-tip",r).tipTip({attribute:"data-tip",fadeIn:50,fadeOut:50,delay:200}))}Array.isArray(_)&&_[0]&&(d=_[0].tracking_number,s=_[0].carrier_code),c&&(o.restrict_order_statuses(r),"pending"===wc_facebook_commerce_orders.order_status&&o.disable_pending_order_related_fields(r),"cancelled"===wc_facebook_commerce_orders.order_status&&o.disable_order_status_field(r),o.maybe_disable_refunds()),c&&(b(),void 0===window.MutationObserver||(e=document.querySelector("#woocommerce-order-items .inside"))&&new MutationObserver(function(e){e.forEach(function(e){Array.prototype.forEach.call(e.addedNodes,function(e){a(e).is(".wc-order-refund-items")&&b()})})}).observe(e,{childList:!0})),n.on("submit",function(e){return!a("#post").data("skip-cancel-modal")&&"wc-cancelled"!==t&&(c&&"wc-cancelled"===r.val())?(e.preventDefault(),a("#wc-backbone-modal-dialog .modal-close").trigger("click"),new a.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:{message:wc_facebook_commerce_orders.cancel_modal_message,buttons:wc_facebook_commerce_orders.cancel_modal_buttons}}),a(".facebook-for-woocommerce-modal #btn-ok").off("click.facebook_for_commerce").on("click.facebook_for_commerce",function(e){e.preventDefault(),e.stopPropagation(),blockModal(),a.post(ajaxurl,{action:wc_facebook_commerce_orders.cancel_order_action,order_id:a("#post_ID").val(),reason_code:a('.facebook-for-woocommerce-modal [name="wc_facebook_cancel_reason"]').val(),security:wc_facebook_commerce_orders.cancel_order_nonce},function(e){e&&e.success?a("#post").data("skip-cancel-modal",!0).trigger("submit"):m(e&&e.data?e.data:wc_facebook_commerce_orders.i18n.unknown_error)}).fail(function(){m(wc_facebook_commerce_orders.i18n.unknown_error)})}),!1):void(c&&!n.data("allow-submit")&&("wc-refunded"===(o=r.val())&&t!==o&&(e.preventDefault(),a("#wc-backbone-modal-dialog .modal-close").trigger("click"),new a.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:{message:wc_facebook_commerce_orders.refund_modal_message,buttons:wc_facebook_commerce_orders.refund_modal_buttons}}),a(document.body).off("wc_backbone_modal_response.facebook_for_commerce").on("wc_backbone_modal_response.facebook_for_commerce",function(){a("#refund_reason").val(a("#wc_facebook_refund_reason_modal").val()),n.data("allow-submit",!0).submit()})),"wc-completed"===o&&(e.preventDefault(),d||s?f(!1,d,s):(a("#wc-backbone-modal-dialog .modal-close").trigger("click"),(l||i)&&a(document.body).off("wc_backbone_modal_loaded").on("wc_backbone_modal_loaded",function(){l&&a("#wc_facebook_carrier").val(l),i&&a("#wc_facebook_tracking_number").val(i)}),new a.WCBackboneModal.View({target:"facebook-for-woocommerce-modal",string:{message:wc_facebook_commerce_orders.complete_modal_message,buttons:wc_facebook_commerce_orders.complete_modal_buttons}}),a(".facebook-for-woocommerce-modal #btn-ok").off("click.facebook_for_commerce").on("click.facebook_for_commerce",function(e){e.preventDefault(),e.stopPropagation(),l=a("#wc_facebook_carrier").val(),f(!0,i=a("#wc_facebook_tracking_number").val(),l)})))));var o})});
assets/js/facebook-for-woocommerce-modal.js CHANGED
@@ -47,4 +47,13 @@
47
  $( '.wc-backbone-modal-content' ).removeClass( 'processing' ).unblock();
48
  }
49
 
 
 
 
 
 
 
 
 
 
50
  })( jQuery );
47
  $( '.wc-backbone-modal-content' ).removeClass( 'processing' ).unblock();
48
  }
49
 
50
+
51
+ /**
52
+ * Closes the current modal.
53
+ */
54
+ window.closeExistingModal = function() {
55
+
56
+ $( '#wc-backbone-modal-dialog .modal-close' ).trigger( 'click' );
57
+ }
58
+
59
  })( jQuery );
assets/js/facebook-for-woocommerce-modal.min.js CHANGED
@@ -1 +1 @@
1
- "use strict";!function(n){window.isModalBlocked=function(){var o=n(".wc-backbone-modal-content");return o.is(".processing")||o.parents(".processing").length},window.blockModal=function(){if(!isModalBlocked())return n(".wc-backbone-modal-content").addClass("processing").block({message:null,overlayCSS:{background:"#fff",opacity:.6}})},window.unBlockModal=function(){n(".wc-backbone-modal-content").removeClass("processing").unblock()}}(jQuery);
1
+ "use strict";!function(n){window.isModalBlocked=function(){var o=n(".wc-backbone-modal-content");return o.is(".processing")||o.parents(".processing").length},window.blockModal=function(){if(!isModalBlocked())return n(".wc-backbone-modal-content").addClass("processing").block({message:null,overlayCSS:{background:"#fff",opacity:.6}})},window.unBlockModal=function(){n(".wc-backbone-modal-content").removeClass("processing").unblock()},window.closeExistingModal=function(){n("#wc-backbone-modal-dialog .modal-close").trigger("click")}}(jQuery);
changelog.txt CHANGED
@@ -1,5 +1,15 @@
1
  *** Facebook for WooCommerce Changelog ***
2
 
 
 
 
 
 
 
 
 
 
 
3
  2020.11.19 - version 2.2.0
4
  * Feature - Add an Advertise tab in the Facebook settings page to manage Facebook ads from within WooCommerce
5
  * Tweak - Move the Facebook settings page into the Marketing menu item (WooCommerce 4.0+)
1
  *** Facebook for WooCommerce Changelog ***
2
 
3
+ 2021.02.16 - version 2.3.0
4
+ * Feature - Add ability to create and assign products to Facebook product sets
5
+ * Feature - Add support for Facebook App store flow
6
+ * Tweak - Ask merchants to delete products when changing from sync to not sync state
7
+ * Tweak - Remove business_management permission from login scopes
8
+ * Tweak - Store paramaters for Commerce merchant settings ID and Instagram business ID
9
+ * Fix - Fix Products::get_google_product_category_id_from_highest_category() to handle WP_Error
10
+ * Fix - Fix random HELLO appearing in the category settings
11
+ * Fix - Make sure that list of strings params are now converted to actual arrays. Fixes an issue with the use of the additional_features parameter
12
+
13
  2020.11.19 - version 2.2.0
14
  * Feature - Add an Advertise tab in the Facebook settings page to manage Facebook ads from within WooCommerce
15
  * Tweak - Move the Facebook settings page into the Marketing menu item (WooCommerce 4.0+)
class-wc-facebookcommerce.php CHANGED
@@ -22,7 +22,7 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
22
 
23
 
24
  /** @var string the plugin version */
25
- const VERSION = '2.2.0';
26
 
27
  /** @var string for backwards compatibility TODO: remove this in v2.0.0 {CW 2020-02-06} */
28
  const PLUGIN_VERSION = self::VERSION;
@@ -33,6 +33,9 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
33
  /** @var string the integration ID */
34
  const INTEGRATION_ID = 'facebookcommerce';
35
 
 
 
 
36
 
37
  /** @var \WC_Facebookcommerce singleton instance */
38
  protected static $instance;
@@ -70,9 +73,15 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
70
  /** @var \SkyVerge\WooCommerce\Facebook\Products\Sync\Background background sync handler */
71
  private $sync_background_handler;
72
 
 
 
 
73
  /** @var \SkyVerge\WooCommerce\Facebook\Handlers\Connection connection handler */
74
  private $connection_handler;
75
 
 
 
 
76
  /** @var \SkyVerge\WooCommerce\Facebook\Integrations\Integrations integrations handler */
77
  private $integrations;
78
 
@@ -107,6 +116,14 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
107
  public function init() {
108
 
109
  add_action( 'init', [ $this, 'get_integration' ] );
 
 
 
 
 
 
 
 
110
 
111
  if ( \WC_Facebookcommerce_Utils::isWoocommerceIntegration() ) {
112
 
@@ -118,6 +135,7 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
118
  require_once __DIR__ . '/includes/Locale.php';
119
  require_once __DIR__ . '/includes/AJAX.php';
120
  require_once __DIR__ . '/includes/Handlers/Connection.php';
 
121
  require_once __DIR__ . '/includes/Integrations/Integrations.php';
122
  require_once __DIR__ . '/includes/Product_Categories.php';
123
  require_once __DIR__ . '/includes/Products.php';
@@ -126,6 +144,7 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
126
  require_once __DIR__ . '/includes/Products/Stock.php';
127
  require_once __DIR__ . '/includes/Products/Sync.php';
128
  require_once __DIR__ . '/includes/Products/Sync/Background.php';
 
129
  require_once __DIR__ . '/includes/fbproductfeed.php';
130
  require_once __DIR__ . '/facebook-commerce-messenger-chat.php';
131
  require_once __DIR__ . '/includes/Commerce.php';
@@ -134,12 +153,13 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
134
  require_once __DIR__ . '/includes/Events/AAMSettings.php';
135
  require_once __DIR__ . '/includes/Utilities/Shipment.php';
136
 
137
- $this->product_feed = new \SkyVerge\WooCommerce\Facebook\Products\Feed();
138
- $this->products_stock_handler = new \SkyVerge\WooCommerce\Facebook\Products\Stock();
139
- $this->products_sync_handler = new \SkyVerge\WooCommerce\Facebook\Products\Sync();
140
- $this->sync_background_handler = new \SkyVerge\WooCommerce\Facebook\Products\Sync\Background();
141
- $this->commerce_handler = new \SkyVerge\WooCommerce\Facebook\Commerce();
142
- $this->fb_categories = new \SkyVerge\WooCommerce\Facebook\Products\FBCategories();
 
143
 
144
  if ( is_ajax() ) {
145
  $this->ajax = new \SkyVerge\WooCommerce\Facebook\AJAX();
@@ -163,6 +183,7 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
163
  }
164
 
165
  $this->connection_handler = new \SkyVerge\WooCommerce\Facebook\Handlers\Connection( $this );
 
166
 
167
  // load admin handlers, before admin_init
168
  if ( is_admin() ) {
@@ -171,6 +192,7 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
171
  require_once __DIR__ . '/includes/Admin/Abstract_Settings_Screen.php';
172
  require_once __DIR__ . '/includes/Admin/Settings_Screens/Connection.php';
173
  require_once __DIR__ . '/includes/Admin/Settings_Screens/Product_Sync.php';
 
174
  require_once __DIR__ . '/includes/Admin/Settings_Screens/Messenger.php';
175
  require_once __DIR__ . '/includes/Admin/Settings_Screens/Advertise.php';
176
  require_once __DIR__ . '/includes/Admin/Google_Product_Category_Field.php';
@@ -366,6 +388,135 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
366
  parent::log_api_request( $request, $response, $log_id );
367
  }
368
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
369
 
370
  /** Getter methods ********************************************************************************************/
371
 
@@ -428,14 +579,6 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
428
  require_once __DIR__ . '/includes/API/Pixel/Events/Request.php';
429
  }
430
 
431
- if ( ! class_exists( API\Business_Manager\Request::class ) ) {
432
- require_once __DIR__ . '/includes/API/Business_Manager/Request.php';
433
- }
434
-
435
- if ( ! class_exists( API\Business_Manager\Response::class ) ) {
436
- require_once __DIR__ . '/includes/API/Business_Manager/Response.php';
437
- }
438
-
439
  if ( ! class_exists( API\Catalog\Request::class ) ) {
440
  require_once __DIR__ . '/includes/API/Catalog/Request.php';
441
  }
@@ -870,6 +1013,24 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
870
  }
871
 
872
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
873
  /** Deprecated methods ****************************************************************************************/
874
 
875
 
22
 
23
 
24
  /** @var string the plugin version */
25
+ const VERSION = '2.3.0';
26
 
27
  /** @var string for backwards compatibility TODO: remove this in v2.0.0 {CW 2020-02-06} */
28
  const PLUGIN_VERSION = self::VERSION;
33
  /** @var string the integration ID */
34
  const INTEGRATION_ID = 'facebookcommerce';
35
 
36
+ /** @var string the product set categories meta name */
37
+ const PRODUCT_SET_META = '_wc_facebook_product_cats';
38
+
39
 
40
  /** @var \WC_Facebookcommerce singleton instance */
41
  protected static $instance;
73
  /** @var \SkyVerge\WooCommerce\Facebook\Products\Sync\Background background sync handler */
74
  private $sync_background_handler;
75
 
76
+ /** @var \SkyVerge\WooCommerce\Facebook\ProductSets\Sync product sets sync handler */
77
+ private $product_sets_sync_handler;
78
+
79
  /** @var \SkyVerge\WooCommerce\Facebook\Handlers\Connection connection handler */
80
  private $connection_handler;
81
 
82
+ /** @var \SkyVerge\WooCommerce\Facebook\Handlers\WebHook webhook handler */
83
+ private $webhook_handler;
84
+
85
  /** @var \SkyVerge\WooCommerce\Facebook\Integrations\Integrations integrations handler */
86
  private $integrations;
87
 
116
  public function init() {
117
 
118
  add_action( 'init', [ $this, 'get_integration' ] );
119
+ add_action( 'init', [ $this, 'register_custom_taxonomy' ] );
120
+ add_action( 'add_meta_boxes_product' , [ $this, 'remove_product_fb_product_set_metabox' ], 50 );
121
+ add_filter( 'fb_product_set_row_actions', [ $this, 'product_set_links' ] );
122
+ add_filter( 'manage_edit-fb_product_set_columns', [ $this, 'manage_fb_product_set_columns' ] );
123
+
124
+ // Product Set breadcrumb filters
125
+ add_filter( 'woocommerce_navigation_is_connected_page', [ $this, 'is_current_page_conected_filter' ], 99, 2 );
126
+ add_filter( 'woocommerce_navigation_get_breadcrumbs', [ $this, 'wc_page_breadcrumbs_filter' ], 99 );
127
 
128
  if ( \WC_Facebookcommerce_Utils::isWoocommerceIntegration() ) {
129
 
135
  require_once __DIR__ . '/includes/Locale.php';
136
  require_once __DIR__ . '/includes/AJAX.php';
137
  require_once __DIR__ . '/includes/Handlers/Connection.php';
138
+ require_once __DIR__ . '/includes/Handlers/WebHook.php';
139
  require_once __DIR__ . '/includes/Integrations/Integrations.php';
140
  require_once __DIR__ . '/includes/Product_Categories.php';
141
  require_once __DIR__ . '/includes/Products.php';
144
  require_once __DIR__ . '/includes/Products/Stock.php';
145
  require_once __DIR__ . '/includes/Products/Sync.php';
146
  require_once __DIR__ . '/includes/Products/Sync/Background.php';
147
+ require_once __DIR__ . '/includes/ProductSets/Sync.php';
148
  require_once __DIR__ . '/includes/fbproductfeed.php';
149
  require_once __DIR__ . '/facebook-commerce-messenger-chat.php';
150
  require_once __DIR__ . '/includes/Commerce.php';
153
  require_once __DIR__ . '/includes/Events/AAMSettings.php';
154
  require_once __DIR__ . '/includes/Utilities/Shipment.php';
155
 
156
+ $this->product_feed = new \SkyVerge\WooCommerce\Facebook\Products\Feed();
157
+ $this->products_stock_handler = new \SkyVerge\WooCommerce\Facebook\Products\Stock();
158
+ $this->products_sync_handler = new \SkyVerge\WooCommerce\Facebook\Products\Sync();
159
+ $this->sync_background_handler = new \SkyVerge\WooCommerce\Facebook\Products\Sync\Background();
160
+ $this->product_sets_sync_handler = new \SkyVerge\WooCommerce\Facebook\ProductSets\Sync();
161
+ $this->commerce_handler = new \SkyVerge\WooCommerce\Facebook\Commerce();
162
+ $this->fb_categories = new \SkyVerge\WooCommerce\Facebook\Products\FBCategories();
163
 
164
  if ( is_ajax() ) {
165
  $this->ajax = new \SkyVerge\WooCommerce\Facebook\AJAX();
183
  }
184
 
185
  $this->connection_handler = new \SkyVerge\WooCommerce\Facebook\Handlers\Connection( $this );
186
+ $this->webhook_handler = new \SkyVerge\WooCommerce\Facebook\Handlers\WebHook( $this );
187
 
188
  // load admin handlers, before admin_init
189
  if ( is_admin() ) {
192
  require_once __DIR__ . '/includes/Admin/Abstract_Settings_Screen.php';
193
  require_once __DIR__ . '/includes/Admin/Settings_Screens/Connection.php';
194
  require_once __DIR__ . '/includes/Admin/Settings_Screens/Product_Sync.php';
195
+ require_once __DIR__ . '/includes/Admin/Settings_Screens/Product_Sets.php';
196
  require_once __DIR__ . '/includes/Admin/Settings_Screens/Messenger.php';
197
  require_once __DIR__ . '/includes/Admin/Settings_Screens/Advertise.php';
198
  require_once __DIR__ . '/includes/Admin/Google_Product_Category_Field.php';
388
  parent::log_api_request( $request, $response, $log_id );
389
  }
390
 
391
+ /**
392
+ * Remove Product Set metabox from Product edit page
393
+ *
394
+ * @since 2.3.0
395
+ */
396
+ public function remove_product_fb_product_set_metabox() {
397
+ remove_meta_box( 'fb_product_setdiv', 'product', 'side' );
398
+ }
399
+
400
+ /**
401
+ * Register FB Product Set Taxonomy
402
+ *
403
+ * @since 2.3.0
404
+ */
405
+ public function register_custom_taxonomy() {
406
+
407
+ $plural = esc_html__( 'FB Product Sets', 'facebook-for-woocommerce' );
408
+ $singular = esc_html__( 'FB Product Set', 'facebook-for-woocommerce' );
409
+
410
+ $args = array(
411
+ 'labels' => array(
412
+ 'name' => $plural,
413
+ 'singular_name' => $singular,
414
+ 'menu_name' => $plural,
415
+ // translators: Edit item label
416
+ 'edit_item' => sprintf( esc_html__( 'Edit %s', 'facebook-for-woocommerce' ), $singular ),
417
+ // translators: Add new label
418
+ 'add_new_item' => sprintf( esc_html__( 'Add new %s', 'facebook-for-woocommerce' ), $singular ),
419
+ 'menu_name' => $plural,
420
+ // translators: No items found text
421
+ 'not_found' => sprintf( esc_html__( 'No %s found.', 'facebook-for-woocommerce' ), $plural ),
422
+ // translators: Search label
423
+ 'search_items' => sprintf( esc_html__( 'Search %s.', 'facebook-for-woocommerce' ), $plural ),
424
+ // translators: Text label
425
+ 'separate_items_with_commas' => sprintf( esc_html__( 'Separate %s with commas', 'facebook-for-woocommerce' ), $plural ),
426
+ // translators: Text label
427
+ 'choose_from_most_used' => sprintf( esc_html__( 'Choose from the most used %s', 'facebook-for-woocommerce' ), $plural ),
428
+ ),
429
+ 'hierarchical' => true,
430
+ 'public' => true,
431
+ 'show_in_nav_menus' => false,
432
+ 'show_tagcloud' => false,
433
+ );
434
+
435
+ register_taxonomy( 'fb_product_set', array( 'product' ), $args );
436
+ }
437
+
438
+
439
+ /**
440
+ * Filter FB Product Set Taxonomy table links
441
+ *
442
+ * @since 2.3.0
443
+ *
444
+ * @param array $actions Item Actions.
445
+ *
446
+ * @return array
447
+ */
448
+ public function product_set_links( $actions ) {
449
+ unset( $actions['inline hide-if-no-js'] );
450
+ unset( $actions['view'] );
451
+ return $actions;
452
+ }
453
+
454
+
455
+ /**
456
+ * Remove posts count column from FB Product Set custom taxonomy
457
+ *
458
+ * @since 2.3.0
459
+ *
460
+ * @param array $columns Taxonomy columns.
461
+ *
462
+ * @return array
463
+ */
464
+ public function manage_fb_product_set_columns( $columns ) {
465
+ unset( $columns['posts'] );
466
+ return $columns;
467
+ }
468
+
469
+
470
+ /**
471
+ * Filter WC Breadcrumbs when the page is FB Product Sets
472
+ *
473
+ * @since 2.3.0
474
+ *
475
+ * @param array $breadcrumbs Page breadcrumbs.
476
+ *
477
+ * @return array
478
+ */
479
+ public function wc_page_breadcrumbs_filter( $breadcrumbs ) {
480
+
481
+ if ( 'edit-fb_product_set' !== $this->get_current_page_id() ) {
482
+ return $breadcrumbs;
483
+ }
484
+
485
+ $breadcrumbs = array(
486
+ array( 'admin.php?page=wc-admin', 'WooCommerce' ),
487
+ array( 'edit.php?post_type=product', 'Products' ),
488
+ );
489
+
490
+ $term_id = empty( $_GET['tag_ID'] ) ? '' : $_GET['tag_ID']; //phpcs:ignore WordPress.Security
491
+
492
+ if ( ! empty( $term_id ) ) {
493
+ $breadcrumbs[] = array( 'edit-tags.php?taxonomy=fb_product_set&post_type=product', 'Products Sets' );
494
+ }
495
+
496
+ $breadcrumbs[] = ( empty( $term_id ) ? 'Product Sets' : 'Edit Product Set' );
497
+
498
+ return $breadcrumbs;
499
+ }
500
+
501
+
502
+ /**
503
+ * Return that FB Product Set page is a WC Conected Page
504
+ *
505
+ * @since 2.3.0
506
+ *
507
+ * @param boolean $is_conected If it's connected or not.
508
+ *
509
+ * @return boolean
510
+ */
511
+ public function is_current_page_conected_filter( $is_conected ) {
512
+
513
+ if ( 'edit-fb_product_set' === $this->get_current_page_id() ) {
514
+ return true;
515
+ }
516
+
517
+ return $is_conected;
518
+ }
519
+
520
 
521
  /** Getter methods ********************************************************************************************/
522
 
579
  require_once __DIR__ . '/includes/API/Pixel/Events/Request.php';
580
  }
581
 
 
 
 
 
 
 
 
 
582
  if ( ! class_exists( API\Catalog\Request::class ) ) {
583
  require_once __DIR__ . '/includes/API/Catalog/Request.php';
584
  }
1013
  }
1014
 
1015
 
1016
+ /**
1017
+ * Return current page ID
1018
+ *
1019
+ * @since 2.3.0
1020
+ *
1021
+ * @return string
1022
+ */
1023
+ protected function get_current_page_id() {
1024
+
1025
+ $current_screen_id = '';
1026
+ $current_screen = get_current_screen();
1027
+ if ( ! empty( $current_screen ) ) {
1028
+ $current_screen_id = $current_screen->id;
1029
+ }
1030
+ return $current_screen_id;
1031
+ }
1032
+
1033
+
1034
  /** Deprecated methods ****************************************************************************************/
1035
 
1036
 
facebook-commerce.php CHANGED
@@ -104,6 +104,9 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
104
  /** @var string the hook for the recurreing action that syncs products */
105
  const ACTION_HOOK_SCHEDULED_RESYNC = 'sync_all_fb_products_using_feed';
106
 
 
 
 
107
 
108
  /** @var string|null the configured product catalog ID */
109
  public $product_catalog_id;
@@ -424,6 +427,10 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
424
  'fb_page_id' => $this->get_facebook_page_id(),
425
  'facebook_jssdk_version' => $this->get_js_sdk_version(),
426
  ] );
 
 
 
 
427
  }
428
 
429
  /**
@@ -889,6 +896,26 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
889
  }
890
 
891
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
892
  /**
893
  * Checks the product type and calls the corresponding on publish method.
894
  *
@@ -898,7 +925,7 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
898
  *
899
  * @param int $wp_id post ID
900
  */
901
- function on_product_save( $wp_id ) {
902
 
903
  $product = wc_get_product( $wp_id );
904
 
@@ -914,7 +941,27 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
914
  $sync_mode = Admin::SYNC_MODE_SYNC_AND_HIDE;
915
  }
916
 
917
- if ( ! $product->is_type( 'variable' ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
918
 
919
  if ( $sync_enabled ) {
920
 
@@ -931,6 +978,11 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
931
  }
932
 
933
  Products::disable_sync_for_products( [ $product ] );
 
 
 
 
 
934
  }
935
  }
936
 
@@ -1017,6 +1069,23 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
1017
  return;
1018
  }
1019
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1020
  if ( $product->is_type( 'variation' ) ) {
1021
 
1022
  $retailer_id = \WC_Facebookcommerce_Utils::get_fb_retailer_id( $product );
@@ -1047,6 +1116,10 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
1047
  $this->delete_product_item( $product_id );
1048
  $this->delete_product_group( $product_id );
1049
  }
 
 
 
 
1050
  }
1051
 
1052
 
@@ -1552,6 +1625,63 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
1552
  */
1553
  }
1554
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1555
  /**
1556
  * Saves settings via AJAX (to preserve window context for onboarding).
1557
  *
@@ -1736,8 +1866,8 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
1736
  * @param array $result
1737
  */
1738
  function display_error_message_from_result( $result ) {
1739
-
1740
- $msg = json_decode( $result['body'] )->error->message;
1741
  $this->display_error_message( $msg );
1742
  }
1743
 
104
  /** @var string the hook for the recurreing action that syncs products */
105
  const ACTION_HOOK_SCHEDULED_RESYNC = 'sync_all_fb_products_using_feed';
106
 
107
+ /** @var string custom taxonomy FB product set ID */
108
+ const FB_PRODUCT_SET_ID = 'fb_product_set_id';
109
+
110
 
111
  /** @var string|null the configured product catalog ID */
112
  public $product_catalog_id;
427
  'fb_page_id' => $this->get_facebook_page_id(),
428
  'facebook_jssdk_version' => $this->get_js_sdk_version(),
429
  ] );
430
+
431
+ // Product Set hooks
432
+ add_action( 'fb_wc_product_set_sync', array( $this, 'create_or_update_product_set_item' ), 99, 2 );
433
+ add_action( 'fb_wc_product_set_delete', array( $this, 'delete_product_set_item' ), 99 );
434
  }
435
 
436
  /**
896
  }
897
 
898
 
899
+ /**
900
+ * Gets the IDs of products marked for deletion from Facebook when removed from Sync.
901
+ *
902
+ * @internal
903
+ *
904
+ * @since 2.3.0
905
+ *
906
+ * @return array
907
+ */
908
+ private function get_removed_from_sync_products_to_delete() {
909
+
910
+ $posted_products = Framework\SV_WC_Helper::get_posted_value( WC_Facebook_Product::FB_REMOVE_FROM_SYNC );
911
+ if ( empty( $posted_products ) ) {
912
+ return [];
913
+ }
914
+
915
+ return array_map( 'absint', explode( ',', $posted_products ) );
916
+ }
917
+
918
+
919
  /**
920
  * Checks the product type and calls the corresponding on publish method.
921
  *
925
  *
926
  * @param int $wp_id post ID
927
  */
928
+ public function on_product_save( $wp_id ) {
929
 
930
  $product = wc_get_product( $wp_id );
931
 
941
  $sync_mode = Admin::SYNC_MODE_SYNC_AND_HIDE;
942
  }
943
 
944
+ $products_to_delete_from_facebook = $this->get_removed_from_sync_products_to_delete();
945
+
946
+ if ( $product->is_type( 'variable' ) ) {
947
+
948
+ // check variations for deletion
949
+ foreach ( $products_to_delete_from_facebook as $delete_product_id ) {
950
+
951
+ $delete_product = wc_get_product( $delete_product_id );
952
+
953
+ if ( empty( $delete_product ) ) {
954
+ continue;
955
+ }
956
+
957
+ if ( Products::is_sync_enabled_for_product( $delete_product ) ) {
958
+ continue;
959
+ }
960
+
961
+ $this->delete_fb_product( $delete_product );
962
+ }
963
+
964
+ } else {
965
 
966
  if ( $sync_enabled ) {
967
 
978
  }
979
 
980
  Products::disable_sync_for_products( [ $product ] );
981
+
982
+ if ( in_array( $wp_id, $products_to_delete_from_facebook, true ) ) {
983
+
984
+ $this->delete_fb_product( $product );
985
+ }
986
  }
987
  }
988
 
1069
  return;
1070
  }
1071
 
1072
+ $this->delete_fb_product( $product );
1073
+ }
1074
+
1075
+
1076
+ /**
1077
+ * Deletes Facebook product.
1078
+ *
1079
+ * @internal
1080
+ *
1081
+ * @since 2.3.0
1082
+ *
1083
+ * @param \WC_Product $product WooCommerce product object
1084
+ */
1085
+ private function delete_fb_product( $product ) {
1086
+
1087
+ $product_id = $product->get_id();
1088
+
1089
  if ( $product->is_type( 'variation' ) ) {
1090
 
1091
  $retailer_id = \WC_Facebookcommerce_Utils::get_fb_retailer_id( $product );
1116
  $this->delete_product_item( $product_id );
1117
  $this->delete_product_group( $product_id );
1118
  }
1119
+
1120
+ // clear out both item and group IDs
1121
+ delete_post_meta( $product_id, self::FB_PRODUCT_ITEM_ID );
1122
+ delete_post_meta( $product_id, self::FB_PRODUCT_GROUP_ID );
1123
  }
1124
 
1125
 
1625
  */
1626
  }
1627
 
1628
+
1629
+ /**
1630
+ * Create or update product set
1631
+ *
1632
+ * @since 2.3.0
1633
+ *
1634
+ * @param array $product_set_data Product Set data.
1635
+ * @param int $product_set_id Product Set Term Id.
1636
+ **/
1637
+ public function create_or_update_product_set_item( $product_set_data, $product_set_id ) {
1638
+
1639
+ // check if exists in FB
1640
+ $fb_product_set_id = get_term_meta( $product_set_id, self::FB_PRODUCT_SET_ID, true );
1641
+
1642
+ // set data and execute API call
1643
+ $method = empty( $fb_product_set_id ) ? 'create' : 'update';
1644
+ $id = empty( $fb_product_set_id ) ? $this->get_product_catalog_id() : $fb_product_set_id;
1645
+ $result = $this->check_api_result(
1646
+ call_user_func_array(
1647
+ array(
1648
+ $this->fbgraph,
1649
+ $method . '_product_set_item',
1650
+ ),
1651
+ array(
1652
+ $id,
1653
+ $product_set_data,
1654
+ )
1655
+ )
1656
+ );
1657
+
1658
+ // update product set to set FB Product Set ID
1659
+ if ( $result && empty( $fb_product_set_id ) ) {
1660
+
1661
+ // decode and get ID from result body
1662
+ $decode_result = WC_Facebookcommerce_Utils::decode_json( $result['body'] );
1663
+ $fb_product_set_id = $decode_result->id;
1664
+
1665
+ update_term_meta(
1666
+ $product_set_id,
1667
+ self::FB_PRODUCT_SET_ID,
1668
+ $fb_product_set_id
1669
+ );
1670
+ }
1671
+ }
1672
+
1673
+
1674
+ /**
1675
+ * Delete product set
1676
+ *
1677
+ * @since 2.3.0
1678
+ *
1679
+ * @param int $fb_product_set_id Facebook Product Set ID.
1680
+ **/
1681
+ public function delete_product_set_item( $fb_product_set_id ) {
1682
+ $this->check_api_result( $this->fbgraph->delete_product_set_item( $fb_product_set_id ) );
1683
+ }
1684
+
1685
  /**
1686
  * Saves settings via AJAX (to preserve window context for onboarding).
1687
  *
1866
  * @param array $result
1867
  */
1868
  function display_error_message_from_result( $result ) {
1869
+ $error = json_decode( $result['body'] )->error;
1870
+ $msg = ( 'Fatal' === $error->message && ! empty( $error->error_user_title ) ) ? $error->error_user_title : $error_message;
1871
  $this->display_error_message( $msg );
1872
  }
1873
 
facebook-for-woocommerce.php CHANGED
@@ -10,10 +10,10 @@
10
  * Description: Grow your business on Facebook! Use this official plugin to help sell more of your products using Facebook. After completing the setup, you'll be ready to create ads that promote your products and you can also create a shop section on your Page where customers can browse your products on Facebook.
11
  * Author: Facebook
12
  * Author URI: https://www.facebook.com/
13
- * Version: 2.2.0
14
  * Text Domain: facebook-for-woocommerce
15
  * WC requires at least: 3.5.0
16
- * WC tested up to: 4.7.0
17
  *
18
  * @package FacebookCommerce
19
  */
10
  * Description: Grow your business on Facebook! Use this official plugin to help sell more of your products using Facebook. After completing the setup, you'll be ready to create ads that promote your products and you can also create a shop section on your Page where customers can browse your products on Facebook.
11
  * Author: Facebook
12
  * Author URI: https://www.facebook.com/
13
+ * Version: 2.3.0
14
  * Text Domain: facebook-for-woocommerce
15
  * WC requires at least: 3.5.0
16
+ * WC tested up to: 5.0.0
17
  *
18
  * @package FacebookCommerce
19
  */
i18n/languages/facebook-for-woocommerce.pot CHANGED
@@ -1,19 +1,19 @@
1
- # Copyright (C) 2020 Facebook
2
  # This file is distributed under the same license as the Facebook for WooCommerce package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: Facebook for WooCommerce 2.2.0\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://woocommerce.com/my-account/marketplace-ticket-form/\n"
8
- "POT-Creation-Date: 2020-11-19 21:10:35+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
- "PO-Revision-Date: 2020-MO-DA HO:MI+ZONE\n"
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
15
 
16
- #: class-wc-facebookcommerce.php:235
17
  #. translators: Placeholders %1$s - opening strong HTML tag, %2$s - closing
18
  #. strong HTML tag, %3$s - opening link HTML tag, %4$s - closing link HTML tag
19
  msgid ""
@@ -21,7 +21,7 @@ msgid ""
21
  "Facebook for WooCommerce connection. Please %3$sclick here%4$s to reconnect!"
22
  msgstr ""
23
 
24
- #: class-wc-facebookcommerce.php:250
25
  #. translators: Placeholders %1$s - opening link HTML tag, %2$s - closing link
26
  #. HTML tag
27
  msgid ""
@@ -29,7 +29,7 @@ msgid ""
29
  "under %1$sWooCommerce > Facebook%2$s."
30
  msgstr ""
31
 
32
- #: class-wc-facebookcommerce.php:265
33
  #. translators: Placeholders %1$s - opening strong HTML tag, %2$s - closing
34
  #. strong HTML tag, %3$s - opening link HTML tag, %4$s - closing link HTML tag
35
  msgid ""
@@ -37,7 +37,7 @@ msgid ""
37
  "configuration, %3$scomplete the setup steps%4$s."
38
  msgstr ""
39
 
40
- #: class-wc-facebookcommerce.php:293
41
  #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
42
  #. <a> tag, %4$s - </a> tag
43
  msgid ""
@@ -46,7 +46,7 @@ msgid ""
46
  "Connection%4$s area."
47
  msgstr ""
48
 
49
- #: class-wc-facebookcommerce.php:310
50
  #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
51
  #. <a> tag, %4$s - </a> tag
52
  msgid ""
@@ -55,13 +55,51 @@ msgid ""
55
  "products."
56
  msgstr ""
57
 
58
- #: class-wc-facebookcommerce.php:330
59
  #. translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing
60
  #. </a> HTML link tag
61
  msgid "Heads up! The Facebook menu is now located under the %1$sMarketing%2$s menu."
62
  msgstr ""
63
 
64
- #: class-wc-facebookcommerce.php:392
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  msgid "Cannot create the API instance because the access token is missing."
66
  msgstr ""
67
 
@@ -69,69 +107,69 @@ msgstr ""
69
  msgid "Facebook for WooCommerce"
70
  msgstr ""
71
 
72
- #: facebook-commerce.php:217
73
  msgid "Facebook Commerce and Dynamic Ads (Pixel) Extension"
74
  msgstr ""
75
 
76
- #: facebook-commerce.php:634
77
  msgid "Facebook ID:"
78
  msgstr ""
79
 
80
- #: facebook-commerce.php:642
81
  msgid "Variant IDs:"
82
  msgstr ""
83
 
84
- #: facebook-commerce.php:660
85
  msgid "Reset Facebook metadata"
86
  msgstr ""
87
 
88
- #: facebook-commerce.php:665
89
  msgid "Delete product(s) on Facebook"
90
  msgstr ""
91
 
92
- #: facebook-commerce.php:673
93
  msgid "This product is not yet synced to Facebook."
94
  msgstr ""
95
 
96
- #: facebook-commerce.php:1423
97
  msgid "Nothing to update for product group for %1$s"
98
  msgstr ""
99
 
100
- #: facebook-commerce.php:1761
101
  #. translators: Placeholders %1$s - original error message from Facebook API
102
  msgid "There was an issue connecting to the Facebook API: %1$s"
103
  msgstr ""
104
 
105
- #: facebook-commerce.php:2098
106
  msgid "Your connection has expired."
107
  msgstr ""
108
 
109
- #: facebook-commerce.php:2098
110
  msgid ""
111
  "Please click Manage connection > Advanced Options > Update Token to refresh "
112
  "your connection to Facebook."
113
  msgstr ""
114
 
115
- #: facebook-commerce.php:2105
116
  #. translators: Placeholders %s - error message
117
  msgid "There was an error trying to sync the products to Facebook. %s"
118
  msgstr ""
119
 
120
- #: facebook-commerce.php:2128 facebook-commerce.php:2301
121
  msgid "Product sync is disabled."
122
  msgstr ""
123
 
124
- #: facebook-commerce.php:2135 facebook-commerce.php:2308
125
  msgid "The plugin is not configured or the Catalog ID is missing."
126
  msgstr ""
127
 
128
- #: facebook-commerce.php:2158
129
  msgid ""
130
  "A product sync is in progress. Please wait until the sync finishes before "
131
  "starting a new one."
132
  msgstr ""
133
 
134
- #: facebook-commerce.php:2170 facebook-commerce.php:2322
135
  msgid ""
136
  "We've detected that your Facebook Product Catalog is no longer valid. This "
137
  "may happen if it was deleted, but could also be a temporary error. If the "
@@ -139,33 +177,33 @@ msgid ""
139
  "and setup the plugin again."
140
  msgstr ""
141
 
142
- #: facebook-commerce.php:2346
143
  msgid "We couldn't create the feed or upload the product information."
144
  msgstr ""
145
 
146
- #: facebook-commerce.php:2814
147
  msgid "Hi! We're here to answer any questions you may have."
148
  msgstr ""
149
 
150
- #: facebook-commerce.php:3161
151
  msgid "Facebook for WooCommerce error:"
152
  msgstr ""
153
 
154
- #: facebook-commerce.php:3243
155
  msgid ""
156
  "There was an error trying to retrieve information about the Facebook page: "
157
  "%s"
158
  msgstr ""
159
 
160
- #: facebook-commerce.php:3294
161
  msgid "Get started with Messenger Customer Chat"
162
  msgstr ""
163
 
164
- #: facebook-commerce.php:3295
165
  msgid "Get started with Instagram Shopping"
166
  msgstr ""
167
 
168
- #: facebook-commerce.php:3530
169
  #. translators: Placeholders %1$s - original error message from Facebook API
170
  msgid "There was an issue connecting to the Facebook API: %s"
171
  msgstr ""
@@ -208,7 +246,7 @@ msgstr ""
208
 
209
  #: includes/AJAX.php:337 includes/AJAX.php:406 includes/AJAX.php:470
210
  #: includes/Admin/Product_Categories.php:118
211
- #: includes/Admin/Settings_Screens/Product_Sync.php:142
212
  msgid "Cancel"
213
  msgstr ""
214
 
@@ -290,6 +328,14 @@ msgstr ""
290
  msgid "Category Specific Attributes"
291
  msgstr ""
292
 
 
 
 
 
 
 
 
 
293
  #: includes/Admin/Products.php:96
294
  msgid "Select values for enhanced attributes for this product"
295
  msgstr ""
@@ -335,20 +381,20 @@ msgstr ""
335
  msgid "Facebook"
336
  msgstr ""
337
 
338
- #: includes/Admin/Settings.php:106
339
  #: includes/Admin/Settings_Screens/Connection.php:34
340
  #: includes/Admin/Settings_Screens/Connection.php:35
341
  msgid "Connection"
342
  msgstr ""
343
 
344
- #: includes/Admin/Settings.php:109
345
  #: includes/Admin/Settings_Screens/Messenger.php:40
346
  #: includes/Admin/Settings_Screens/Messenger.php:41
347
  #: includes/Admin/Settings_Screens/Messenger.php:144
348
  msgid "Messenger"
349
  msgstr ""
350
 
351
- #: includes/Admin/Settings.php:112
352
  #: includes/Admin/Settings_Screens/Product_Sync.php:42
353
  #: includes/Admin/Settings_Screens/Product_Sync.php:43
354
  #: includes/Admin/Settings_Screens/Product_Sync.php:167
@@ -356,21 +402,21 @@ msgstr ""
356
  msgid "Product sync"
357
  msgstr ""
358
 
359
- #: includes/Admin/Settings.php:115
360
  #: includes/Admin/Settings_Screens/Advertise.php:37
361
  #: includes/Admin/Settings_Screens/Advertise.php:38
362
  msgid "Advertise"
363
  msgstr ""
364
 
365
- #: includes/Admin/Settings.php:197
366
  msgid "You do not have permission to save these settings."
367
  msgstr ""
368
 
369
- #: includes/Admin/Settings.php:206
370
  msgid "Your settings have been saved."
371
  msgstr ""
372
 
373
- #: includes/Admin/Settings.php:213
374
  #. translators: Placeholders: %s - user-friendly error message
375
  msgid "Your settings could not be saved. %s"
376
  msgstr ""
@@ -416,55 +462,63 @@ msgstr ""
416
  msgid "Ad Manager account"
417
  msgstr ""
418
 
419
- #: includes/Admin/Settings_Screens/Connection.php:253
 
 
 
 
 
 
 
 
420
  msgid "Reach the Right People and Sell More Online"
421
  msgstr ""
422
 
423
- #: includes/Admin/Settings_Screens/Connection.php:255
424
  msgid "Grow your business on Facebook"
425
  msgstr ""
426
 
427
- #: includes/Admin/Settings_Screens/Connection.php:258
428
  msgid "Use this WooCommerce and Facebook integration to:"
429
  msgstr ""
430
 
431
- #: includes/Admin/Settings_Screens/Connection.php:260
432
  msgid "Create an ad in a few steps"
433
  msgstr ""
434
 
435
- #: includes/Admin/Settings_Screens/Connection.php:261
436
  msgid "Use built-in best practices for online sales"
437
  msgstr ""
438
 
439
- #: includes/Admin/Settings_Screens/Connection.php:262
440
  msgid "Get reporting on sales and revenue"
441
  msgstr ""
442
 
443
- #: includes/Admin/Settings_Screens/Connection.php:285
444
  msgid "Manage Connection"
445
  msgstr ""
446
 
447
- #: includes/Admin/Settings_Screens/Connection.php:289
448
  msgid "Uninstall"
449
  msgstr ""
450
 
451
- #: includes/Admin/Settings_Screens/Connection.php:295
452
  msgid "Get Started"
453
  msgstr ""
454
 
455
- #: includes/Admin/Settings_Screens/Connection.php:320
456
  msgid "Debug"
457
  msgstr ""
458
 
459
- #: includes/Admin/Settings_Screens/Connection.php:326
460
  msgid "Enable debug mode"
461
  msgstr ""
462
 
463
- #: includes/Admin/Settings_Screens/Connection.php:328
464
  msgid "Log plugin events for debugging"
465
  msgstr ""
466
 
467
- #: includes/Admin/Settings_Screens/Connection.php:329
468
  msgid "Only enable this if you are experiencing problems with the plugin."
469
  msgstr ""
470
 
@@ -505,6 +559,11 @@ msgstr ""
505
  msgid "Please try again."
506
  msgstr ""
507
 
 
 
 
 
 
508
  #: includes/Admin/Settings_Screens/Product_Sync.php:71
509
  #. translators: Placeholders: {count} number of remaining items
510
  msgid "{count} item remaining."
@@ -611,41 +670,45 @@ msgstr ""
611
  msgid "Please %1$sconnect to Facebook%2$s to enable and manage product sync."
612
  msgstr ""
613
 
614
- #: includes/Admin.php:144
 
 
 
 
615
  msgid ""
616
  "Please enter a Google product category and at least one sub-category to "
617
  "sell this product on Instagram."
618
  msgstr ""
619
 
620
- #: includes/Admin.php:166
621
  msgid "Search main categories..."
622
  msgstr ""
623
 
624
- #: includes/Admin.php:167
625
  msgid "Choose a main category"
626
  msgstr ""
627
 
628
- #: includes/Admin.php:168
629
  msgid "Choose a category"
630
  msgstr ""
631
 
632
- #: includes/Admin.php:207
633
  msgid ""
634
  "To sell this product on Instagram, please ensure it meets the following "
635
  "requirements:"
636
  msgstr ""
637
 
638
- #: includes/Admin.php:210
639
  msgid "Has a price defined"
640
  msgstr ""
641
 
642
- #: includes/Admin.php:213
643
  #. translators: Placeholders: %1$s - <strong> opening HTML tag, %2$s -
644
  #. </strong> closing HTML tag
645
  msgid "Has %1$sManage Stock%2$s enabled on the %1$sInventory%2$s tab"
646
  msgstr ""
647
 
648
- #: includes/Admin.php:219
649
  #. translators: Placeholders: %1$s - <strong> opening HTML tag, %2$s -
650
  #. </strong> closing HTML tag
651
  msgid ""
@@ -653,40 +716,57 @@ msgid ""
653
  "and hide\""
654
  msgstr ""
655
 
656
- #: includes/Admin.php:245
657
  msgid "Close"
658
  msgstr ""
659
 
660
- #: includes/Admin.php:277 includes/Admin.php:1121 includes/Admin.php:1256
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
661
  msgid "Facebook sync"
662
  msgstr ""
663
 
664
- #: includes/Admin.php:304 includes/Admin.php:336
665
  msgid "Sync and show"
666
  msgstr ""
667
 
668
- #: includes/Admin.php:306 includes/Admin.php:337
669
  msgid "Sync and hide"
670
  msgstr ""
671
 
672
- #: includes/Admin.php:311 includes/Admin.php:338 includes/Admin.php:1125
673
- #: includes/Admin.php:1260
674
  msgid "Do not sync"
675
  msgstr ""
676
 
677
- #: includes/Admin.php:335
678
  msgid "Filter by Facebook sync setting"
679
  msgstr ""
680
 
681
- #: includes/Admin.php:748
682
  msgid "Include in Facebook sync"
683
  msgstr ""
684
 
685
- #: includes/Admin.php:749
686
  msgid "Exclude from Facebook sync"
687
  msgstr ""
688
 
689
- #: includes/Admin.php:942
690
  #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
691
  #. <a> tag, %4$s - <a> tag
692
  msgid ""
@@ -700,11 +780,11 @@ msgid_plural ""
700
  msgstr[0] ""
701
  msgstr[1] ""
702
 
703
- #: includes/Admin.php:949
704
  msgid "Don't show this notice again"
705
  msgstr ""
706
 
707
- #: includes/Admin.php:983
708
  #. translators: Placeholders: %1$s - number of affected products, %2$s opening
709
  #. HTML <a> tag, %3$s - closing HTML </a> tag, %4$s - opening HTML <a> tag,
710
  #. %5$s - closing HTML </a> tag
@@ -721,7 +801,7 @@ msgid_plural ""
721
  msgstr[0] ""
722
  msgstr[1] ""
723
 
724
- #: includes/Admin.php:1049
725
  #. translators: Placeholders: %1$s - opening HTML <strong> tag, %2$s - closing
726
  #. HTML </strong> tag, %3$s - opening HTML <a> tag, %4$s - closing HTML </a>
727
  #. tag
@@ -731,69 +811,69 @@ msgid ""
731
  "your Facebook catalog. You may still advertise Virtual products on Facebook."
732
  msgstr ""
733
 
734
- #: includes/Admin.php:1123 includes/Admin.php:1258
735
  msgid "Sync and show in catalog"
736
  msgstr ""
737
 
738
- #: includes/Admin.php:1124 includes/Admin.php:1259
739
  msgid "Sync and hide in catalog"
740
  msgstr ""
741
 
742
- #: includes/Admin.php:1134 includes/Admin.php:1272
743
  msgid "Facebook Description"
744
  msgstr ""
745
 
746
- #: includes/Admin.php:1136 includes/Admin.php:1274
747
  msgid ""
748
  "Custom (plain-text only) description for product on Facebook. If blank, "
749
  "product description will be used. If product description is blank, "
750
  "shortname will be used."
751
  msgstr ""
752
 
753
- #: includes/Admin.php:1147 includes/Admin.php:1287
754
  msgid "Facebook Product Image"
755
  msgstr ""
756
 
757
- #: includes/Admin.php:1149 includes/Admin.php:1289
758
  msgid ""
759
  "Choose the product image that should be synced to the Facebook catalog for "
760
  "this product. If using a custom image, please enter an absolute URL (e.g. "
761
  "https://domain.com/image.jpg)."
762
  msgstr ""
763
 
764
- #: includes/Admin.php:1151
765
  msgid "Use WooCommerce image"
766
  msgstr ""
767
 
768
- #: includes/Admin.php:1152 includes/Admin.php:1293
769
  msgid "Use custom image"
770
  msgstr ""
771
 
772
- #: includes/Admin.php:1163 includes/Admin.php:1305
773
  msgid "Custom Image URL"
774
  msgstr ""
775
 
776
- #: includes/Admin.php:1174 includes/Admin.php:1318
777
  #. translators: Placeholders %1$s - WC currency symbol
778
  msgid "Facebook Price (%1$s)"
779
  msgstr ""
780
 
781
- #: includes/Admin.php:1178 includes/Admin.php:1322
782
  msgid ""
783
  "Custom price for product on Facebook. Please enter in monetary decimal (.) "
784
  "format without thousand separators and currency symbols. If blank, product "
785
  "price will be used."
786
  msgstr ""
787
 
788
- #: includes/Admin.php:1291
789
  msgid "Use variation image"
790
  msgstr ""
791
 
792
- #: includes/Admin.php:1292
793
  msgid "Use parent image"
794
  msgstr ""
795
 
796
- #: includes/Admin.php:1445
797
  msgid "Close modal panel"
798
  msgstr ""
799
 
@@ -878,32 +958,36 @@ msgstr ""
878
  msgid "Other"
879
  msgstr ""
880
 
881
- #: includes/Handlers/Connection.php:275
882
  msgid "Connection complete! Thanks for using Facebook for WooCommerce."
883
  msgstr ""
884
 
885
- #: includes/Handlers/Connection.php:301
886
  msgid "You do not have permission to uninstall Facebook Business Extension."
887
  msgstr ""
888
 
889
- #: includes/Handlers/Connection.php:311
890
  msgid "Uninstall successful"
891
  msgstr ""
892
 
893
- #: includes/Handlers/Connection.php:317
894
  msgid "Uninstall unsuccessful. Please try again."
895
  msgstr ""
896
 
897
- #: includes/Handlers/Connection.php:372
898
  #. translators: Placeholders: %s - API error message
899
  msgid "Could not retrieve page access data. %s"
900
  msgstr ""
901
 
902
- #: includes/Handlers/Connection.php:384
903
  #. translators: Placeholders: %s - Facebook page ID
904
  msgid "Page %s not authorized."
905
  msgstr ""
906
 
 
 
 
 
907
  #: includes/Products/Sync/Background.php:65
908
  msgid "Job data key \"%s\" not set"
909
  msgstr ""
1
+ # Copyright (C) 2021 Facebook
2
  # This file is distributed under the same license as the Facebook for WooCommerce package.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: Facebook for WooCommerce 2.3.0\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://woocommerce.com/my-account/marketplace-ticket-form/\n"
8
+ "POT-Creation-Date: 2021-02-16 15:58:50+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
+ "PO-Revision-Date: 2021-MO-DA HO:MI+ZONE\n"
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
15
 
16
+ #: class-wc-facebookcommerce.php:257
17
  #. translators: Placeholders %1$s - opening strong HTML tag, %2$s - closing
18
  #. strong HTML tag, %3$s - opening link HTML tag, %4$s - closing link HTML tag
19
  msgid ""
21
  "Facebook for WooCommerce connection. Please %3$sclick here%4$s to reconnect!"
22
  msgstr ""
23
 
24
+ #: class-wc-facebookcommerce.php:272
25
  #. translators: Placeholders %1$s - opening link HTML tag, %2$s - closing link
26
  #. HTML tag
27
  msgid ""
29
  "under %1$sWooCommerce > Facebook%2$s."
30
  msgstr ""
31
 
32
+ #: class-wc-facebookcommerce.php:287
33
  #. translators: Placeholders %1$s - opening strong HTML tag, %2$s - closing
34
  #. strong HTML tag, %3$s - opening link HTML tag, %4$s - closing link HTML tag
35
  msgid ""
37
  "configuration, %3$scomplete the setup steps%4$s."
38
  msgstr ""
39
 
40
+ #: class-wc-facebookcommerce.php:315
41
  #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
42
  #. <a> tag, %4$s - </a> tag
43
  msgid ""
46
  "Connection%4$s area."
47
  msgstr ""
48
 
49
+ #: class-wc-facebookcommerce.php:332
50
  #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
51
  #. <a> tag, %4$s - </a> tag
52
  msgid ""
55
  "products."
56
  msgstr ""
57
 
58
+ #: class-wc-facebookcommerce.php:352
59
  #. translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing
60
  #. </a> HTML link tag
61
  msgid "Heads up! The Facebook menu is now located under the %1$sMarketing%2$s menu."
62
  msgstr ""
63
 
64
+ #: class-wc-facebookcommerce.php:407
65
+ msgid "FB Product Sets"
66
+ msgstr ""
67
+
68
+ #: class-wc-facebookcommerce.php:408
69
+ msgid "FB Product Set"
70
+ msgstr ""
71
+
72
+ #: class-wc-facebookcommerce.php:416
73
+ #. translators: Edit item label
74
+ msgid "Edit %s"
75
+ msgstr ""
76
+
77
+ #: class-wc-facebookcommerce.php:418
78
+ #. translators: Add new label
79
+ msgid "Add new %s"
80
+ msgstr ""
81
+
82
+ #: class-wc-facebookcommerce.php:421
83
+ #. translators: No items found text
84
+ msgid "No %s found."
85
+ msgstr ""
86
+
87
+ #: class-wc-facebookcommerce.php:423
88
+ #. translators: Search label
89
+ msgid "Search %s."
90
+ msgstr ""
91
+
92
+ #: class-wc-facebookcommerce.php:425
93
+ #. translators: Text label
94
+ msgid "Separate %s with commas"
95
+ msgstr ""
96
+
97
+ #: class-wc-facebookcommerce.php:427
98
+ #. translators: Text label
99
+ msgid "Choose from the most used %s"
100
+ msgstr ""
101
+
102
+ #: class-wc-facebookcommerce.php:543
103
  msgid "Cannot create the API instance because the access token is missing."
104
  msgstr ""
105
 
107
  msgid "Facebook for WooCommerce"
108
  msgstr ""
109
 
110
+ #: facebook-commerce.php:220
111
  msgid "Facebook Commerce and Dynamic Ads (Pixel) Extension"
112
  msgstr ""
113
 
114
+ #: facebook-commerce.php:641
115
  msgid "Facebook ID:"
116
  msgstr ""
117
 
118
+ #: facebook-commerce.php:649
119
  msgid "Variant IDs:"
120
  msgstr ""
121
 
122
+ #: facebook-commerce.php:667
123
  msgid "Reset Facebook metadata"
124
  msgstr ""
125
 
126
+ #: facebook-commerce.php:672
127
  msgid "Delete product(s) on Facebook"
128
  msgstr ""
129
 
130
+ #: facebook-commerce.php:680
131
  msgid "This product is not yet synced to Facebook."
132
  msgstr ""
133
 
134
+ #: facebook-commerce.php:1496
135
  msgid "Nothing to update for product group for %1$s"
136
  msgstr ""
137
 
138
+ #: facebook-commerce.php:1891
139
  #. translators: Placeholders %1$s - original error message from Facebook API
140
  msgid "There was an issue connecting to the Facebook API: %1$s"
141
  msgstr ""
142
 
143
+ #: facebook-commerce.php:2228
144
  msgid "Your connection has expired."
145
  msgstr ""
146
 
147
+ #: facebook-commerce.php:2228
148
  msgid ""
149
  "Please click Manage connection > Advanced Options > Update Token to refresh "
150
  "your connection to Facebook."
151
  msgstr ""
152
 
153
+ #: facebook-commerce.php:2235
154
  #. translators: Placeholders %s - error message
155
  msgid "There was an error trying to sync the products to Facebook. %s"
156
  msgstr ""
157
 
158
+ #: facebook-commerce.php:2258 facebook-commerce.php:2431
159
  msgid "Product sync is disabled."
160
  msgstr ""
161
 
162
+ #: facebook-commerce.php:2265 facebook-commerce.php:2438
163
  msgid "The plugin is not configured or the Catalog ID is missing."
164
  msgstr ""
165
 
166
+ #: facebook-commerce.php:2288
167
  msgid ""
168
  "A product sync is in progress. Please wait until the sync finishes before "
169
  "starting a new one."
170
  msgstr ""
171
 
172
+ #: facebook-commerce.php:2300 facebook-commerce.php:2452
173
  msgid ""
174
  "We've detected that your Facebook Product Catalog is no longer valid. This "
175
  "may happen if it was deleted, but could also be a temporary error. If the "
177
  "and setup the plugin again."
178
  msgstr ""
179
 
180
+ #: facebook-commerce.php:2476
181
  msgid "We couldn't create the feed or upload the product information."
182
  msgstr ""
183
 
184
+ #: facebook-commerce.php:2944
185
  msgid "Hi! We're here to answer any questions you may have."
186
  msgstr ""
187
 
188
+ #: facebook-commerce.php:3291
189
  msgid "Facebook for WooCommerce error:"
190
  msgstr ""
191
 
192
+ #: facebook-commerce.php:3373
193
  msgid ""
194
  "There was an error trying to retrieve information about the Facebook page: "
195
  "%s"
196
  msgstr ""
197
 
198
+ #: facebook-commerce.php:3424
199
  msgid "Get started with Messenger Customer Chat"
200
  msgstr ""
201
 
202
+ #: facebook-commerce.php:3425
203
  msgid "Get started with Instagram Shopping"
204
  msgstr ""
205
 
206
+ #: facebook-commerce.php:3660
207
  #. translators: Placeholders %1$s - original error message from Facebook API
208
  msgid "There was an issue connecting to the Facebook API: %s"
209
  msgstr ""
246
 
247
  #: includes/AJAX.php:337 includes/AJAX.php:406 includes/AJAX.php:470
248
  #: includes/Admin/Product_Categories.php:118
249
+ #: includes/Admin/Settings_Screens/Product_Sync.php:142 includes/Admin.php:340
250
  msgid "Cancel"
251
  msgstr ""
252
 
328
  msgid "Category Specific Attributes"
329
  msgstr ""
330
 
331
+ #: includes/Admin/Product_Sets.php:149
332
+ msgid "WC Product Categories"
333
+ msgstr ""
334
+
335
+ #: includes/Admin/Product_Sets.php:181
336
+ msgid "Map FB Product Set to WC Product Categories"
337
+ msgstr ""
338
+
339
  #: includes/Admin/Products.php:96
340
  msgid "Select values for enhanced attributes for this product"
341
  msgstr ""
381
  msgid "Facebook"
382
  msgstr ""
383
 
384
+ #: includes/Admin/Settings.php:107
385
  #: includes/Admin/Settings_Screens/Connection.php:34
386
  #: includes/Admin/Settings_Screens/Connection.php:35
387
  msgid "Connection"
388
  msgstr ""
389
 
390
+ #: includes/Admin/Settings.php:110
391
  #: includes/Admin/Settings_Screens/Messenger.php:40
392
  #: includes/Admin/Settings_Screens/Messenger.php:41
393
  #: includes/Admin/Settings_Screens/Messenger.php:144
394
  msgid "Messenger"
395
  msgstr ""
396
 
397
+ #: includes/Admin/Settings.php:113
398
  #: includes/Admin/Settings_Screens/Product_Sync.php:42
399
  #: includes/Admin/Settings_Screens/Product_Sync.php:43
400
  #: includes/Admin/Settings_Screens/Product_Sync.php:167
402
  msgid "Product sync"
403
  msgstr ""
404
 
405
+ #: includes/Admin/Settings.php:116
406
  #: includes/Admin/Settings_Screens/Advertise.php:37
407
  #: includes/Admin/Settings_Screens/Advertise.php:38
408
  msgid "Advertise"
409
  msgstr ""
410
 
411
+ #: includes/Admin/Settings.php:198
412
  msgid "You do not have permission to save these settings."
413
  msgstr ""
414
 
415
+ #: includes/Admin/Settings.php:207
416
  msgid "Your settings have been saved."
417
  msgstr ""
418
 
419
+ #: includes/Admin/Settings.php:214
420
  #. translators: Placeholders: %s - user-friendly error message
421
  msgid "Your settings could not be saved. %s"
422
  msgstr ""
462
  msgid "Ad Manager account"
463
  msgstr ""
464
 
465
+ #: includes/Admin/Settings_Screens/Connection.php:144
466
+ msgid "Instagram Business ID"
467
+ msgstr ""
468
+
469
+ #: includes/Admin/Settings_Screens/Connection.php:148
470
+ msgid "Commerce Merchant Settings ID"
471
+ msgstr ""
472
+
473
+ #: includes/Admin/Settings_Screens/Connection.php:243
474
  msgid "Reach the Right People and Sell More Online"
475
  msgstr ""
476
 
477
+ #: includes/Admin/Settings_Screens/Connection.php:245
478
  msgid "Grow your business on Facebook"
479
  msgstr ""
480
 
481
+ #: includes/Admin/Settings_Screens/Connection.php:248
482
  msgid "Use this WooCommerce and Facebook integration to:"
483
  msgstr ""
484
 
485
+ #: includes/Admin/Settings_Screens/Connection.php:250
486
  msgid "Create an ad in a few steps"
487
  msgstr ""
488
 
489
+ #: includes/Admin/Settings_Screens/Connection.php:251
490
  msgid "Use built-in best practices for online sales"
491
  msgstr ""
492
 
493
+ #: includes/Admin/Settings_Screens/Connection.php:252
494
  msgid "Get reporting on sales and revenue"
495
  msgstr ""
496
 
497
+ #: includes/Admin/Settings_Screens/Connection.php:275
498
  msgid "Manage Connection"
499
  msgstr ""
500
 
501
+ #: includes/Admin/Settings_Screens/Connection.php:279
502
  msgid "Uninstall"
503
  msgstr ""
504
 
505
+ #: includes/Admin/Settings_Screens/Connection.php:285
506
  msgid "Get Started"
507
  msgstr ""
508
 
509
+ #: includes/Admin/Settings_Screens/Connection.php:310
510
  msgid "Debug"
511
  msgstr ""
512
 
513
+ #: includes/Admin/Settings_Screens/Connection.php:316
514
  msgid "Enable debug mode"
515
  msgstr ""
516
 
517
+ #: includes/Admin/Settings_Screens/Connection.php:318
518
  msgid "Log plugin events for debugging"
519
  msgstr ""
520
 
521
+ #: includes/Admin/Settings_Screens/Connection.php:319
522
  msgid "Only enable this if you are experiencing problems with the plugin."
523
  msgstr ""
524
 
559
  msgid "Please try again."
560
  msgstr ""
561
 
562
+ #: includes/Admin/Settings_Screens/Product_Sets.php:33
563
+ #: includes/Admin/Settings_Screens/Product_Sets.php:34
564
+ msgid "Product Sets"
565
+ msgstr ""
566
+
567
  #: includes/Admin/Settings_Screens/Product_Sync.php:71
568
  #. translators: Placeholders: {count} number of remaining items
569
  msgid "{count} item remaining."
670
  msgid "Please %1$sconnect to Facebook%2$s to enable and manage product sync."
671
  msgstr ""
672
 
673
+ #: includes/Admin.php:116
674
+ msgid "The name is how it appears on Facebook Catalog."
675
+ msgstr ""
676
+
677
+ #: includes/Admin.php:181
678
  msgid ""
679
  "Please enter a Google product category and at least one sub-category to "
680
  "sell this product on Instagram."
681
  msgstr ""
682
 
683
+ #: includes/Admin.php:203
684
  msgid "Search main categories..."
685
  msgstr ""
686
 
687
+ #: includes/Admin.php:204
688
  msgid "Choose a main category"
689
  msgstr ""
690
 
691
+ #: includes/Admin.php:205
692
  msgid "Choose a category"
693
  msgstr ""
694
 
695
+ #: includes/Admin.php:244
696
  msgid ""
697
  "To sell this product on Instagram, please ensure it meets the following "
698
  "requirements:"
699
  msgstr ""
700
 
701
+ #: includes/Admin.php:247
702
  msgid "Has a price defined"
703
  msgstr ""
704
 
705
+ #: includes/Admin.php:250
706
  #. translators: Placeholders: %1$s - <strong> opening HTML tag, %2$s -
707
  #. </strong> closing HTML tag
708
  msgid "Has %1$sManage Stock%2$s enabled on the %1$sInventory%2$s tab"
709
  msgstr ""
710
 
711
+ #: includes/Admin.php:256
712
  #. translators: Placeholders: %1$s - <strong> opening HTML tag, %2$s -
713
  #. </strong> closing HTML tag
714
  msgid ""
716
  "and hide\""
717
  msgstr ""
718
 
719
+ #: includes/Admin.php:282
720
  msgid "Close"
721
  msgstr ""
722
 
723
+ #: includes/Admin.php:305
724
+ #. translators: Placeholders: %1$s - opening <a> link tag, %2$s - closing </a>
725
+ #. link tag
726
+ msgid ""
727
+ "You're removing a product from the Facebook sync that is currently listed "
728
+ "in your %1$sFacebook catalog%2$s. Would you like to delete the product from "
729
+ "the Facebook catalog as well?"
730
+ msgstr ""
731
+
732
+ #: includes/Admin.php:332
733
+ msgid "Remove from sync only"
734
+ msgstr ""
735
+
736
+ #: includes/Admin.php:336
737
+ msgid "Remove from sync and delete"
738
+ msgstr ""
739
+
740
+ #: includes/Admin.php:372 includes/Admin.php:1216 includes/Admin.php:1356
741
  msgid "Facebook sync"
742
  msgstr ""
743
 
744
+ #: includes/Admin.php:399 includes/Admin.php:431
745
  msgid "Sync and show"
746
  msgstr ""
747
 
748
+ #: includes/Admin.php:401 includes/Admin.php:432
749
  msgid "Sync and hide"
750
  msgstr ""
751
 
752
+ #: includes/Admin.php:406 includes/Admin.php:433 includes/Admin.php:1220
753
+ #: includes/Admin.php:1360
754
  msgid "Do not sync"
755
  msgstr ""
756
 
757
+ #: includes/Admin.php:430
758
  msgid "Filter by Facebook sync setting"
759
  msgstr ""
760
 
761
+ #: includes/Admin.php:843
762
  msgid "Include in Facebook sync"
763
  msgstr ""
764
 
765
+ #: includes/Admin.php:844
766
  msgid "Exclude from Facebook sync"
767
  msgstr ""
768
 
769
+ #: includes/Admin.php:1037
770
  #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
771
  #. <a> tag, %4$s - <a> tag
772
  msgid ""
780
  msgstr[0] ""
781
  msgstr[1] ""
782
 
783
+ #: includes/Admin.php:1044
784
  msgid "Don't show this notice again"
785
  msgstr ""
786
 
787
+ #: includes/Admin.php:1078
788
  #. translators: Placeholders: %1$s - number of affected products, %2$s opening
789
  #. HTML <a> tag, %3$s - closing HTML </a> tag, %4$s - opening HTML <a> tag,
790
  #. %5$s - closing HTML </a> tag
801
  msgstr[0] ""
802
  msgstr[1] ""
803
 
804
+ #: includes/Admin.php:1144
805
  #. translators: Placeholders: %1$s - opening HTML <strong> tag, %2$s - closing
806
  #. HTML </strong> tag, %3$s - opening HTML <a> tag, %4$s - closing HTML </a>
807
  #. tag
811
  "your Facebook catalog. You may still advertise Virtual products on Facebook."
812
  msgstr ""
813
 
814
+ #: includes/Admin.php:1218 includes/Admin.php:1358
815
  msgid "Sync and show in catalog"
816
  msgstr ""
817
 
818
+ #: includes/Admin.php:1219 includes/Admin.php:1359
819
  msgid "Sync and hide in catalog"
820
  msgstr ""
821
 
822
+ #: includes/Admin.php:1229 includes/Admin.php:1372
823
  msgid "Facebook Description"
824
  msgstr ""
825
 
826
+ #: includes/Admin.php:1231 includes/Admin.php:1374
827
  msgid ""
828
  "Custom (plain-text only) description for product on Facebook. If blank, "
829
  "product description will be used. If product description is blank, "
830
  "shortname will be used."
831
  msgstr ""
832
 
833
+ #: includes/Admin.php:1242 includes/Admin.php:1387
834
  msgid "Facebook Product Image"
835
  msgstr ""
836
 
837
+ #: includes/Admin.php:1244 includes/Admin.php:1389
838
  msgid ""
839
  "Choose the product image that should be synced to the Facebook catalog for "
840
  "this product. If using a custom image, please enter an absolute URL (e.g. "
841
  "https://domain.com/image.jpg)."
842
  msgstr ""
843
 
844
+ #: includes/Admin.php:1246
845
  msgid "Use WooCommerce image"
846
  msgstr ""
847
 
848
+ #: includes/Admin.php:1247 includes/Admin.php:1393
849
  msgid "Use custom image"
850
  msgstr ""
851
 
852
+ #: includes/Admin.php:1258 includes/Admin.php:1405
853
  msgid "Custom Image URL"
854
  msgstr ""
855
 
856
+ #: includes/Admin.php:1269 includes/Admin.php:1418
857
  #. translators: Placeholders %1$s - WC currency symbol
858
  msgid "Facebook Price (%1$s)"
859
  msgstr ""
860
 
861
+ #: includes/Admin.php:1273 includes/Admin.php:1422
862
  msgid ""
863
  "Custom price for product on Facebook. Please enter in monetary decimal (.) "
864
  "format without thousand separators and currency symbols. If blank, product "
865
  "price will be used."
866
  msgstr ""
867
 
868
+ #: includes/Admin.php:1391
869
  msgid "Use variation image"
870
  msgstr ""
871
 
872
+ #: includes/Admin.php:1392
873
  msgid "Use parent image"
874
  msgstr ""
875
 
876
+ #: includes/Admin.php:1545
877
  msgid "Close modal panel"
878
  msgstr ""
879
 
958
  msgid "Other"
959
  msgstr ""
960
 
961
+ #: includes/Handlers/Connection.php:310
962
  msgid "Connection complete! Thanks for using Facebook for WooCommerce."
963
  msgstr ""
964
 
965
+ #: includes/Handlers/Connection.php:336
966
  msgid "You do not have permission to uninstall Facebook Business Extension."
967
  msgstr ""
968
 
969
+ #: includes/Handlers/Connection.php:346
970
  msgid "Uninstall successful"
971
  msgstr ""
972
 
973
+ #: includes/Handlers/Connection.php:352
974
  msgid "Uninstall unsuccessful. Please try again."
975
  msgstr ""
976
 
977
+ #: includes/Handlers/Connection.php:409
978
  #. translators: Placeholders: %s - API error message
979
  msgid "Could not retrieve page access data. %s"
980
  msgstr ""
981
 
982
+ #: includes/Handlers/Connection.php:421
983
  #. translators: Placeholders: %s - Facebook page ID
984
  msgid "Page %s not authorized."
985
  msgstr ""
986
 
987
+ #: includes/Handlers/Connection.php:1357
988
+ msgid "You do not have permission to finish App Store login."
989
+ msgstr ""
990
+
991
  #: includes/Products/Sync/Background.php:65
992
  msgid "Job data key \"%s\" not set"
993
  msgstr ""
includes/API.php CHANGED
@@ -261,25 +261,6 @@ class API extends Framework\SV_WC_API_Base {
261
  }
262
 
263
 
264
- /**
265
- * Gets a business manager object from Facebook.
266
- *
267
- * @since 2.0.0
268
- *
269
- * @param string $business_manager_id business manager ID
270
- * @return API\Business_Manager\Response
271
- * @throws Framework\SV_WC_API_Exception
272
- */
273
- public function get_business_manager( $business_manager_id ) {
274
-
275
- $request = new API\Business_Manager\Request( $business_manager_id );
276
-
277
- $this->set_response_handler( API\Business_Manager\Response::class );
278
-
279
- return $this->perform_request( $request );
280
- }
281
-
282
-
283
  /**
284
  * Gets a Catalog object from Facebook.
285
  *
261
  }
262
 
263
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
  /**
265
  * Gets a Catalog object from Facebook.
266
  *
includes/API/Business_Manager/Request.php DELETED
@@ -1,51 +0,0 @@
1
- <?php
2
- /**
3
- * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
4
- *
5
- * This source code is licensed under the license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- *
8
- * @package FacebookCommerce
9
- */
10
-
11
- namespace SkyVerge\WooCommerce\Facebook\API\Business_Manager;
12
-
13
- defined( 'ABSPATH' ) or exit;
14
-
15
- use SkyVerge\WooCommerce\Facebook\API;
16
-
17
- /**
18
- * Request object for the Business Manager API.
19
- *
20
- * @since 2.0.0
21
- */
22
- class Request extends API\Request {
23
-
24
-
25
- /**
26
- * API request constructor.
27
- *
28
- * @since 2.0.0
29
- *
30
- * @param string $business_manager_id business manager ID
31
- */
32
- public function __construct( $business_manager_id ) {
33
-
34
- parent::__construct( "/{$business_manager_id}", 'GET' );
35
- }
36
-
37
-
38
- /**
39
- * Gets the request parameters.
40
- *
41
- * @since 2.0.0
42
- *
43
- * @return array
44
- */
45
- public function get_params() {
46
-
47
- return [ 'fields' => 'name,link' ];
48
- }
49
-
50
-
51
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/API/Business_Manager/Response.php DELETED
@@ -1,49 +0,0 @@
1
- <?php
2
- /**
3
- * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
4
- *
5
- * This source code is licensed under the license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- *
8
- * @package FacebookCommerce
9
- */
10
-
11
- namespace SkyVerge\WooCommerce\Facebook\API\Business_Manager;
12
-
13
- defined( 'ABSPATH' ) or exit;
14
-
15
- /**
16
- * Business Manager API response object
17
- *
18
- * @since 2.0.0
19
- */
20
- class Response extends \SkyVerge\WooCommerce\Facebook\API\Response {
21
-
22
-
23
- /**
24
- * Gets the business manager name.
25
- *
26
- * @since 2.0.0
27
- *
28
- * @return string|null
29
- */
30
- public function get_name() {
31
-
32
- return $this->name;
33
- }
34
-
35
-
36
- /**
37
- * Gets the business manager name.
38
- *
39
- * @since 2.0.0
40
- *
41
- * @return string|null
42
- */
43
- public function get_url() {
44
-
45
- return $this->link;
46
- }
47
-
48
-
49
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/API/FBE/Installation/Read/Response.php CHANGED
@@ -89,6 +89,38 @@ class Response extends API\Response {
89
  }
90
 
91
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  /**
93
  * Gets the profiles.
94
  *
89
  }
90
 
91
 
92
+ /**
93
+ * Gets Instagram Business ID.
94
+ *
95
+ * @since 2.1.5
96
+ *
97
+ * @return string
98
+ */
99
+ public function get_instagram_business_id() {
100
+
101
+ $instagram_profiles = ! empty( $this->get_data()->instagram_profiles ) ? $this->get_data()->instagram_profiles : '';
102
+
103
+ if ( empty( $instagram_profiles ) ) {
104
+ return '';
105
+ }
106
+
107
+ return is_array( $instagram_profiles ) ? current( $instagram_profiles ) : $instagram_profiles;
108
+ }
109
+
110
+
111
+ /**
112
+ * Gets the commerce merchant settings ID.
113
+ *
114
+ * @since 2.1.5
115
+ *
116
+ * @return string
117
+ */
118
+ public function get_commerce_merchant_settings_id() {
119
+
120
+ return ! empty( $this->get_data()->commerce_merchant_settings_id ) ? $this->get_data()->commerce_merchant_settings_id : '';
121
+ }
122
+
123
+
124
  /**
125
  * Gets the profiles.
126
  *
includes/Admin.php CHANGED
@@ -54,8 +54,10 @@ class Admin {
54
 
55
  require_once __DIR__ . '/Admin/Products.php';
56
  require_once __DIR__ . '/Admin/Product_Categories.php';
 
57
 
58
  $this->product_categories = new Admin\Product_Categories();
 
59
 
60
  // add a modal in admin product pages
61
  add_action( 'admin_footer', array( $this, 'render_modal_template' ) );
@@ -91,8 +93,31 @@ class Admin {
91
  // add Variation edit fields
92
  add_action( 'woocommerce_product_after_variable_attributes', array( $this, 'add_product_variation_edit_fields' ), 10, 3 );
93
  add_action( 'woocommerce_save_product_variation', array( $this, 'save_product_variation_edit_fields' ), 10, 2 );
 
 
 
94
  }
95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
  /**
98
  * Enqueues admin scripts.
@@ -119,6 +144,15 @@ class Admin {
119
  wp_enqueue_script( 'facebook-for-woocommerce-modal', facebook_for_woocommerce()->get_plugin_url() . '/assets/js/facebook-for-woocommerce-modal.min.js', array( 'jquery', 'wc-backbone-modal', 'jquery-blockui' ), \WC_Facebookcommerce::PLUGIN_VERSION );
120
  }
121
 
 
 
 
 
 
 
 
 
 
122
  if ( 'product' === $current_screen->id || 'edit-product' === $current_screen->id ) {
123
 
124
  wp_enqueue_style( 'facebook-for-woocommerce-products-admin', facebook_for_woocommerce()->get_plugin_url() . '/assets/css/admin/facebook-for-woocommerce-products-admin.css', array(), \WC_Facebookcommerce::PLUGIN_VERSION );
@@ -128,22 +162,25 @@ class Admin {
128
  wp_localize_script(
129
  'facebook-for-woocommerce-products-admin',
130
  'facebook_for_woocommerce_products_admin',
131
- array(
132
- 'ajax_url' => admin_url( 'admin-ajax.php' ),
133
- 'enhanced_attribute_optional_selector' => \SkyVerge\WooCommerce\Facebook\Admin\Enhanced_Catalog_Attribute_Fields::FIELD_ENHANCED_CATALOG_ATTRIBUTE_PREFIX . \SkyVerge\WooCommerce\Facebook\Admin\Enhanced_Catalog_Attribute_Fields::OPTIONAL_SELECTOR_KEY,
134
- 'enhanced_attribute_page_type_edit_category' => \SkyVerge\WooCommerce\Facebook\Admin\Enhanced_Catalog_Attribute_Fields::PAGE_TYPE_EDIT_CATEGORY,
135
- 'enhanced_attribute_page_type_add_category' => \SkyVerge\WooCommerce\Facebook\Admin\Enhanced_Catalog_Attribute_Fields::PAGE_TYPE_ADD_CATEGORY,
136
- 'enhanced_attribute_page_type_edit_product' => \SkyVerge\WooCommerce\Facebook\Admin\Enhanced_Catalog_Attribute_Fields::PAGE_TYPE_EDIT_PRODUCT,
137
- 'is_sync_enabled_for_product' => $this->is_sync_enabled_for_current_product(),
138
- 'set_product_visibility_nonce' => wp_create_nonce( 'set-products-visibility' ),
139
- 'set_product_sync_prompt_nonce' => wp_create_nonce( 'set-product-sync-prompt' ),
140
- 'set_product_sync_bulk_action_prompt_nonce' => wp_create_nonce( 'set-product-sync-bulk-action-prompt' ),
141
- 'product_not_ready_modal_message' => $this->get_product_not_ready_modal_message(),
142
- 'product_not_ready_modal_buttons' => $this->get_product_not_ready_modal_buttons(),
143
- 'i18n' => array(
 
 
 
144
  'missing_google_product_category_message' => __( 'Please enter a Google product category and at least one sub-category to sell this product on Instagram.', 'facebook-for-woocommerce' ),
145
- ),
146
- )
147
  );
148
 
149
  }//end if
@@ -249,6 +286,64 @@ class Admin {
249
  }
250
 
251
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
  /**
253
  * Gets the product category admin handler instance.
254
  *
@@ -1183,6 +1278,11 @@ class Admin {
1183
  )
1184
  );
1185
 
 
 
 
 
 
1186
  ?>
1187
  </div>
1188
 
54
 
55
  require_once __DIR__ . '/Admin/Products.php';
56
  require_once __DIR__ . '/Admin/Product_Categories.php';
57
+ require_once __DIR__ . '/Admin/Product_Sets.php';
58
 
59
  $this->product_categories = new Admin\Product_Categories();
60
+ $this->product_sets = new Admin\Product_Sets();
61
 
62
  // add a modal in admin product pages
63
  add_action( 'admin_footer', array( $this, 'render_modal_template' ) );
93
  // add Variation edit fields
94
  add_action( 'woocommerce_product_after_variable_attributes', array( $this, 'add_product_variation_edit_fields' ), 10, 3 );
95
  add_action( 'woocommerce_save_product_variation', array( $this, 'save_product_variation_edit_fields' ), 10, 2 );
96
+
97
+ // add custom taxonomy for Product Sets
98
+ add_filter( 'gettext', array( $this, 'change_custom_taxonomy_tip' ), 20, 2 );
99
  }
100
 
101
+ /**
102
+ * Change custom taxonomy tip text
103
+ *
104
+ * @since 2.3.0
105
+ *
106
+ * @param string $translation Text translation.
107
+ * @param string $text Original text.
108
+ *
109
+ * @return string
110
+ */
111
+ public function change_custom_taxonomy_tip( $translation, $text ) {
112
+
113
+ global $current_screen;
114
+
115
+ if ( isset( $current_screen->id ) && 'edit-fb_product_set' === $current_screen->id && 'The name is how it appears on your site.' === $text ) {
116
+ $translation = esc_html__( 'The name is how it appears on Facebook Catalog.', 'facebook-for-woocommerce' );
117
+ }
118
+
119
+ return $translation;
120
+ }
121
 
122
  /**
123
  * Enqueues admin scripts.
144
  wp_enqueue_script( 'facebook-for-woocommerce-modal', facebook_for_woocommerce()->get_plugin_url() . '/assets/js/facebook-for-woocommerce-modal.min.js', array( 'jquery', 'wc-backbone-modal', 'jquery-blockui' ), \WC_Facebookcommerce::PLUGIN_VERSION );
145
  }
146
 
147
+ if ( 'edit-fb_product_set' === $current_screen->id ) {
148
+
149
+ // enqueue WooCommerce Admin Styles because of Select2
150
+ wp_enqueue_style( 'woocommerce_admin_styles', WC()->plugin_url() . '/assets/css/admin.css', array(), \WC_Facebookcommerce::PLUGIN_VERSION );
151
+ wp_enqueue_style( 'facebook-for-woocommerce-product-sets-admin', facebook_for_woocommerce()->get_plugin_url() . '/assets/css/admin/facebook-for-woocommerce-product-sets-admin.css', array(), \WC_Facebookcommerce::PLUGIN_VERSION );
152
+
153
+ wp_enqueue_script( 'facebook-for-woocommerce-product-sets', facebook_for_woocommerce()->get_plugin_url() . '/assets/js/admin/facebook-for-woocommerce-product-sets-admin.js', array( 'jquery', 'select2' ), \WC_Facebookcommerce::PLUGIN_VERSION, true );
154
+ }
155
+
156
  if ( 'product' === $current_screen->id || 'edit-product' === $current_screen->id ) {
157
 
158
  wp_enqueue_style( 'facebook-for-woocommerce-products-admin', facebook_for_woocommerce()->get_plugin_url() . '/assets/css/admin/facebook-for-woocommerce-products-admin.css', array(), \WC_Facebookcommerce::PLUGIN_VERSION );
162
  wp_localize_script(
163
  'facebook-for-woocommerce-products-admin',
164
  'facebook_for_woocommerce_products_admin',
165
+ [
166
+ 'ajax_url' => admin_url( 'admin-ajax.php' ),
167
+ 'enhanced_attribute_optional_selector' => \SkyVerge\WooCommerce\Facebook\Admin\Enhanced_Catalog_Attribute_Fields::FIELD_ENHANCED_CATALOG_ATTRIBUTE_PREFIX . \SkyVerge\WooCommerce\Facebook\Admin\Enhanced_Catalog_Attribute_Fields::OPTIONAL_SELECTOR_KEY,
168
+ 'enhanced_attribute_page_type_edit_category' => \SkyVerge\WooCommerce\Facebook\Admin\Enhanced_Catalog_Attribute_Fields::PAGE_TYPE_EDIT_CATEGORY,
169
+ 'enhanced_attribute_page_type_add_category' => \SkyVerge\WooCommerce\Facebook\Admin\Enhanced_Catalog_Attribute_Fields::PAGE_TYPE_ADD_CATEGORY,
170
+ 'enhanced_attribute_page_type_edit_product' => \SkyVerge\WooCommerce\Facebook\Admin\Enhanced_Catalog_Attribute_Fields::PAGE_TYPE_EDIT_PRODUCT,
171
+ 'is_sync_enabled_for_product' => $this->is_sync_enabled_for_current_product(),
172
+ 'set_product_visibility_nonce' => wp_create_nonce( 'set-products-visibility' ),
173
+ 'set_product_sync_prompt_nonce' => wp_create_nonce( 'set-product-sync-prompt' ),
174
+ 'set_product_sync_bulk_action_prompt_nonce' => wp_create_nonce( 'set-product-sync-bulk-action-prompt' ),
175
+ 'product_not_ready_modal_message' => $this->get_product_not_ready_modal_message(),
176
+ 'product_not_ready_modal_buttons' => $this->get_product_not_ready_modal_buttons(),
177
+ 'product_removed_from_sync_confirm_modal_message' => $this->get_product_removed_from_sync_confirm_modal_message(),
178
+ 'product_removed_from_sync_confirm_modal_buttons' => $this->get_product_removed_from_sync_confirm_modal_buttons(),
179
+ 'product_removed_from_sync_field_id' => '#' . \WC_Facebook_Product::FB_REMOVE_FROM_SYNC,
180
+ 'i18n' => [
181
  'missing_google_product_category_message' => __( 'Please enter a Google product category and at least one sub-category to sell this product on Instagram.', 'facebook-for-woocommerce' ),
182
+ ],
183
+ ]
184
  );
185
 
186
  }//end if
286
  }
287
 
288
 
289
+ /**
290
+ * Gets the markup for the message used in the product removed from sync confirm modal.
291
+ *
292
+ * @internal
293
+ *
294
+ * @since 2.3.0
295
+ *
296
+ * @return string
297
+ */
298
+ private function get_product_removed_from_sync_confirm_modal_message() {
299
+
300
+ ob_start();
301
+
302
+ ?>
303
+ <p><?php printf(
304
+ /* translators: Placeholders: %1$s - opening <a> link tag, %2$s - closing </a> link tag */
305
+ __( 'You\'re removing a product from the Facebook sync that is currently listed in your %1$sFacebook catalog%2$s. Would you like to delete the product from the Facebook catalog as well?', 'facebook-for-woocommerce' ),
306
+ '<a href="https://www.facebook.com/products" target="_blank">',
307
+ '</a>'
308
+ ); ?></p>
309
+ <?php
310
+
311
+ return ob_get_clean();
312
+ }
313
+
314
+
315
+ /**
316
+ * Gets the markup for the buttons used in the product removed from sync confirm modal.
317
+ *
318
+ * @internal
319
+ *
320
+ * @since 2.3.0
321
+ *
322
+ * @return string
323
+ */
324
+ private function get_product_removed_from_sync_confirm_modal_buttons() {
325
+
326
+ ob_start();
327
+
328
+ ?>
329
+ <button
330
+ id="btn-ok"
331
+ class="button button-large button-primary"
332
+ ><?php esc_html_e( 'Remove from sync only', 'facebook-for-woocomerce' ); ?></button>
333
+
334
+ <button
335
+ class="button button-large button-delete button-product-removed-from-sync-delete"
336
+ ><?php esc_html_e( 'Remove from sync and delete', 'facebook-for-woocomerce' ); ?></button>
337
+
338
+ <button
339
+ class="button button-large button-product-removed-from-sync-cancel"
340
+ ><?php esc_html_e( 'Cancel', 'facebook-for-woocomerce' ); ?></button>
341
+ <?php
342
+
343
+ return ob_get_clean();
344
+ }
345
+
346
+
347
  /**
348
  * Gets the product category admin handler instance.
349
  *
1278
  )
1279
  );
1280
 
1281
+ woocommerce_wp_hidden_input( [
1282
+ 'id' => \WC_Facebook_Product::FB_REMOVE_FROM_SYNC,
1283
+ 'value' => '',
1284
+ ] );
1285
+
1286
  ?>
1287
  </div>
1288
 
includes/Admin/Product_Categories.php CHANGED
@@ -284,7 +284,7 @@ class Product_Categories {
284
  ?>
285
  <tr class='form-field'>
286
  <td colspan="2">
287
- <span>HELLO<?php echo $category_id; ?></span>
288
  </td>
289
  </tr>
290
  <?php
284
  ?>
285
  <tr class='form-field'>
286
  <td colspan="2">
287
+ <span><?php echo $category_id; ?></span>
288
  </td>
289
  </tr>
290
  <?php
includes/Admin/Product_Sets.php ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
4
+ *
5
+ * This source code is licensed under the license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ * @package FacebookCommerce
9
+ */
10
+
11
+ namespace SkyVerge\WooCommerce\Facebook\Admin;
12
+
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+ use SkyVerge\WooCommerce\PluginFramework\v5_5_4 as Framework;
18
+
19
+ /**
20
+ * General handler for the product set admin functionality.
21
+ *
22
+ * @since 2.3.0
23
+ */
24
+ class Product_Sets {
25
+
26
+ /**
27
+ * Allowed HTML for wp_kses
28
+ *
29
+ * @since 2.3.0
30
+ *
31
+ * @var array
32
+ */
33
+ protected $allowed_html = array(
34
+ 'label' => array(
35
+ 'for' => array(),
36
+ ),
37
+ 'input' => array(
38
+ 'type' => array(),
39
+ 'name' => array(),
40
+ 'id' => array(),
41
+ ),
42
+ 'p' => array(
43
+ 'class' => array(),
44
+ ),
45
+ );
46
+
47
+ /**
48
+ * Categories field name
49
+ *
50
+ * @since 2.3.0
51
+ *
52
+ * @var string
53
+ */
54
+ protected $categories_field = '';
55
+
56
+
57
+ /**
58
+ * Handler constructor.
59
+ *
60
+ * @since 2.3.0
61
+ */
62
+ public function __construct() {
63
+
64
+ $this->categories_field = \WC_Facebookcommerce::PRODUCT_SET_META;
65
+
66
+ // add taxonomy custom field
67
+ add_action( 'fb_product_set_add_form_fields', array( $this, 'category_field_on_new' ) );
68
+ add_action( 'fb_product_set_edit_form', array( $this, 'category_field_on_edit' ) );
69
+
70
+ // save custom field data
71
+ add_action( 'created_fb_product_set', array( $this, 'save_custom_field' ), 10, 2 );
72
+ add_action( 'edited_fb_product_set', array( $this, 'save_custom_field' ), 10, 2 );
73
+ }
74
+
75
+
76
+ /**
77
+ * Add field to FB Product Set new term
78
+ *
79
+ * @since 2.3.0
80
+ */
81
+ public function category_field_on_new() {
82
+ ?>
83
+ <div class="form-field">
84
+ <?php echo wp_kses( $this->get_field_label(), $this->allowed_html ); ?>
85
+ <?php echo wp_kses( $this->get_field(), $this->allowed_html ); ?>
86
+ </div>
87
+ <?php
88
+ }
89
+
90
+
91
+ /**
92
+ * Add field to FB Product Set new term
93
+ *
94
+ * @since 2.3.0
95
+ *
96
+ * @param WP_Term $term Term object.
97
+ */
98
+ public function category_field_on_edit( $term ) {
99
+
100
+ // gets term id
101
+ $term_id = empty( $term->term_id ) ? '' : $term->term_id;
102
+
103
+ ?>
104
+ <table class="form-table" role="presentation">
105
+ <tbody>
106
+ <tr class="form-field product-categories-wrap">
107
+ <th scope="row"><?php echo wp_kses( $this->get_field_label(), $this->allowed_html ); ?></th>
108
+ <td><?php echo wp_kses( $this->get_field( $term_id ), $this->allowed_html ); ?></td>
109
+ </tr>
110
+ </tbody>
111
+ </table>
112
+
113
+ <?php
114
+ }
115
+
116
+
117
+ /**
118
+ * Saves custom field data
119
+ *
120
+ * @since 2.3.0
121
+ *
122
+ * @param int $term_id Term ID.
123
+ * @param int $tt_id Term taxonomy ID.
124
+ */
125
+ public function save_custom_field( $term_id, $tt_id ) {
126
+
127
+ $wc_product_cats = empty( $_POST[ $this->categories_field ] ) ? '' : $_POST[ $this->categories_field ]; //phpcs:ignore
128
+ if ( ! empty( $wc_product_cats ) ) {
129
+
130
+ $wc_product_cats = array_map(
131
+ function( $item ) {
132
+ return absint( $item );
133
+ },
134
+ $wc_product_cats
135
+ );
136
+ }
137
+
138
+ update_term_meta( $term_id, $this->categories_field, $wc_product_cats );
139
+ }
140
+
141
+
142
+ /**
143
+ * Return field label HTML
144
+ *
145
+ * @since 2.3.0
146
+ */
147
+ protected function get_field_label() {
148
+ ?>
149
+ <label for="<?php echo esc_attr( $this->categories_field ); ?>"><?php echo esc_html__( 'WC Product Categories', 'facebook-for-woocommerce' ); ?></label>
150
+ <?php
151
+ }
152
+
153
+
154
+ /**
155
+ * Return field HTML
156
+ *
157
+ * @since 2.3.0
158
+ *
159
+ * @param int $term_id The Term ID that is editing.
160
+ */
161
+ protected function get_field( $term_id = '' ) {
162
+
163
+ $saved_items = get_term_meta( $term_id, $this->categories_field, true );
164
+ $product_cats = get_terms( 'product_cat', array( 'hide_empty' => 0 ) );
165
+
166
+ ?>
167
+ <div class="select2 updating-message"><p></p></div>
168
+ <select
169
+ id="<?php echo esc_attr( $this->categories_field ); ?>"
170
+ name="<?php echo esc_attr( $this->categories_field ); ?>[]"
171
+ multiple="multiple"
172
+ disabled="disabled"
173
+ class="select2 wc-facebook product_cats"
174
+ style="display:none;"
175
+ >
176
+ <?php foreach ( $product_cats as $product_cat ) : ?>
177
+ <?php $selected = ( is_array( $saved_items ) && in_array( $product_cat->term_id, $saved_items, true ) ) ? ' selected="selected"' : ''; ?>
178
+ <option value="<?php echo esc_attr( $product_cat->term_id ); ?>" <?php echo esc_attr( $selected ); ?>><?php echo esc_attr( $product_cat->name ); ?></option>
179
+ <?php endforeach; ?>
180
+ <select>
181
+ <p class="description"><?php echo esc_html__( 'Map FB Product Set to WC Product Categories', 'facebook-for-woocommerce' ); ?>.</p>
182
+ <?php
183
+ }
184
+ }
includes/Admin/Settings.php CHANGED
@@ -41,6 +41,7 @@ class Settings {
41
  $this->screens = array(
42
  Settings_Screens\Connection::ID => new Settings_Screens\Connection(),
43
  Settings_Screens\Product_Sync::ID => new Settings_Screens\Product_Sync(),
 
44
  Settings_Screens\Messenger::ID => new Settings_Screens\Messenger(),
45
  Settings_Screens\Advertise::ID => new Settings_Screens\Advertise(),
46
  );
41
  $this->screens = array(
42
  Settings_Screens\Connection::ID => new Settings_Screens\Connection(),
43
  Settings_Screens\Product_Sync::ID => new Settings_Screens\Product_Sync(),
44
+ Settings_Screens\Product_Sets::ID => new Settings_Screens\Product_Sets(),
45
  Settings_Screens\Messenger::ID => new Settings_Screens\Messenger(),
46
  Settings_Screens\Advertise::ID => new Settings_Screens\Advertise(),
47
  );
includes/Admin/Settings_Screens/Connection.php CHANGED
@@ -140,6 +140,14 @@ class Connection extends Admin\Abstract_Settings_Screen {
140
  'label' => __( 'Ad Manager account', 'facebook-for-woocommerce' ),
141
  'value' => facebook_for_woocommerce()->get_connection_handler()->get_ad_account_id(),
142
  ],
 
 
 
 
 
 
 
 
143
  ];
144
 
145
  // if the catalog ID is set, update the URL and try to get its name for display
@@ -158,24 +166,6 @@ class Connection extends Admin\Abstract_Settings_Screen {
158
  } catch ( Framework\SV_WC_API_Exception $exception ) {}
159
  }
160
 
161
- // if the business manager ID is set, try and get its name for display
162
- if ( $static_items['business-manager']['value'] ) {
163
-
164
- try {
165
-
166
- $response = facebook_for_woocommerce()->get_api()->get_business_manager( $static_items['business-manager']['value'] );
167
-
168
- if ( $name = $response->get_name() ) {
169
- $static_items['business-manager']['value'] = $name;
170
- }
171
-
172
- if ( $url = $response->get_url() ) {
173
- $static_items['business-manager']['url'] = $url;
174
- }
175
-
176
- } catch ( Framework\SV_WC_API_Exception $exception ) {}
177
- }
178
-
179
  ?>
180
 
181
  <table class="form-table">
140
  'label' => __( 'Ad Manager account', 'facebook-for-woocommerce' ),
141
  'value' => facebook_for_woocommerce()->get_connection_handler()->get_ad_account_id(),
142
  ],
143
+ 'instagram-business-id' => [
144
+ 'label' => __( 'Instagram Business ID', 'facebook-for-woocommerce' ),
145
+ 'value' => facebook_for_woocommerce()->get_connection_handler()->get_instagram_business_id(),
146
+ ],
147
+ 'commerce-merchant-settings-id' => [
148
+ 'label' => __( 'Commerce Merchant Settings ID', 'facebook-for-woocommerce' ),
149
+ 'value' => facebook_for_woocommerce()->get_connection_handler()->get_commerce_merchant_settings_id(),
150
+ ],
151
  ];
152
 
153
  // if the catalog ID is set, update the URL and try to get its name for display
166
  } catch ( Framework\SV_WC_API_Exception $exception ) {}
167
  }
168
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  ?>
170
 
171
  <table class="form-table">
includes/Admin/Settings_Screens/Product_Sets.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
4
+ *
5
+ * This source code is licensed under the license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ * @package FacebookCommerce
9
+ */
10
+
11
+ namespace SkyVerge\WooCommerce\Facebook\Admin\Settings_Screens;
12
+
13
+ defined( 'ABSPATH' ) or exit;
14
+
15
+ use SkyVerge\WooCommerce\Facebook\Admin;
16
+ use SkyVerge\WooCommerce\PluginFramework\v5_5_4\SV_WC_Helper;
17
+
18
+ /**
19
+ * The Product sets redirect object.
20
+ */
21
+ class Product_Sets extends Admin\Abstract_Settings_Screen {
22
+
23
+
24
+ /** @var string screen ID */
25
+ const ID = 'product_sets';
26
+
27
+ /**
28
+ * Connection constructor.
29
+ */
30
+ public function __construct() {
31
+
32
+ $this->id = self::ID;
33
+ $this->label = __( 'Product Sets', 'facebook-for-woocommerce' );
34
+ $this->title = __( 'Product Sets', 'facebook-for-woocommerce' );
35
+ }
36
+
37
+ public function render() {
38
+ wp_safe_redirect( admin_url( 'edit-tags.php?taxonomy=fb_product_set&post_type=product' ) );
39
+ exit;
40
+ }
41
+
42
+ public function get_settings() {}
43
+ }
includes/Handlers/Connection.php CHANGED
@@ -32,12 +32,21 @@ class Connection {
32
  /** @var string WooCommerce connection proxy URL */
33
  const PROXY_URL = 'https://connect.woocommerce.com/auth/facebook/';
34
 
 
 
 
 
 
 
35
  /** @var string the action callback for the connection */
36
  const ACTION_CONNECT = 'wc_facebook_connect';
37
 
38
  /** @var string the action callback for the disconnection */
39
  const ACTION_DISCONNECT = 'wc_facebook_disconnect';
40
 
 
 
 
41
  /** @var string the action callback for the connection */
42
  const ACTION_CONNECT_COMMERCE = 'wc_facebook_connect_commerce';
43
 
@@ -65,6 +74,18 @@ class Connection {
65
  /** @var string the Commerce manager ID option name */
66
  const OPTION_COMMERCE_MANAGER_ID = 'wc_facebook_commerce_manager_id';
67
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  /** @var string|null the generated external merchant settings ID */
69
  private $external_business_id;
70
 
@@ -88,6 +109,12 @@ class Connection {
88
  add_action( 'woocommerce_api_' . self::ACTION_CONNECT, [ $this, 'handle_connect' ] );
89
 
90
  add_action( 'admin_action_' . self::ACTION_DISCONNECT, [ $this, 'handle_disconnect' ] );
 
 
 
 
 
 
91
  }
92
 
93
 
@@ -214,6 +241,14 @@ class Connection {
214
  if ( $response->get_ad_account_id() ) {
215
  $this->update_ad_account_id( sanitize_text_field( $response->get_ad_account_id() ) );
216
  }
 
 
 
 
 
 
 
 
217
  }
218
 
219
 
@@ -336,6 +371,8 @@ class Connection {
336
  $this->update_system_user_id( '' );
337
  $this->update_business_manager_id( '' );
338
  $this->update_ad_account_id( '' );
 
 
339
 
340
  update_option( \WC_Facebookcommerce_Integration::SETTING_FACEBOOK_PAGE_ID, '' );
341
  update_option( \WC_Facebookcommerce_Integration::SETTING_FACEBOOK_PIXEL_ID, '' );
@@ -564,10 +601,10 @@ class Connection {
564
  $scopes = [
565
  'manage_business_extension',
566
  'catalog_management',
567
- 'business_management',
568
  'ads_management',
569
  'ads_read',
570
  'pages_read_engagement', // this scope is needed to enable order management if using the Commerce feature
 
571
  ];
572
 
573
  /**
@@ -716,6 +753,32 @@ class Connection {
716
  }
717
 
718
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
719
  /**
720
  * Gets the proxy URL.
721
  *
@@ -736,6 +799,26 @@ class Connection {
736
  }
737
 
738
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
739
  /**
740
  * Gets the full redirect URL where the user will return to after OAuth.
741
  *
@@ -749,6 +832,7 @@ class Connection {
749
  'wc-api' => self::ACTION_CONNECT,
750
  'external_business_id' => $this->get_external_business_id(),
751
  'nonce' => wp_create_nonce( self::ACTION_CONNECT ),
 
752
  ], home_url( '/' ) );
753
 
754
  /**
@@ -815,6 +899,8 @@ class Connection {
815
  'timezone' => $this->get_timezone_string(),
816
  'currency' => get_woocommerce_currency(),
817
  'business_vertical' => 'ECOMMERCE',
 
 
818
  ],
819
  'business_config' => [
820
  'business' => [
@@ -917,6 +1003,32 @@ class Connection {
917
  }
918
 
919
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
920
  /**
921
  * Stores the given token value.
922
  *
@@ -1032,4 +1144,246 @@ class Connection {
1032
  }
1033
 
1034
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1035
  }
32
  /** @var string WooCommerce connection proxy URL */
33
  const PROXY_URL = 'https://connect.woocommerce.com/auth/facebook/';
34
 
35
+ /** @var string WooCommerce connection for APP Store login URL */
36
+ const APP_STORE_LOGIN_URL = 'https://connect.woocommerce.com/app-store-login/facebook/';
37
+
38
+ /** @var string the Standard Auth type */
39
+ const AUTH_TYPE_STANDARD = 'standard';
40
+
41
  /** @var string the action callback for the connection */
42
  const ACTION_CONNECT = 'wc_facebook_connect';
43
 
44
  /** @var string the action callback for the disconnection */
45
  const ACTION_DISCONNECT = 'wc_facebook_disconnect';
46
 
47
+ /** @var string the action callback for FBE redirection */
48
+ const ACTION_FBE_REDIRECT = 'wc_fbe_redirect';
49
+
50
  /** @var string the action callback for the connection */
51
  const ACTION_CONNECT_COMMERCE = 'wc_facebook_connect_commerce';
52
 
74
  /** @var string the Commerce manager ID option name */
75
  const OPTION_COMMERCE_MANAGER_ID = 'wc_facebook_commerce_manager_id';
76
 
77
+ /** @var string webhook event subscribed object */
78
+ const WEBHOOK_SUBSCRIBED_OBJECT = 'user';
79
+
80
+ /** @var string webhook event subscribed field */
81
+ const WEBHOOK_SUBSCRIBED_FIELD = 'fbe_install';
82
+
83
+ /** @var string Instagram Business ID option name */
84
+ const OPTION_INSTAGRAM_BUSINESS_ID = 'wc_facebook_instagram_business_id';
85
+
86
+ /** @var string the Commerce merchant settings ID option name */
87
+ const OPTION_COMMERCE_MERCHANT_SETTINGS_ID = 'wc_facebook_commerce_merchant_settings_id';
88
+
89
  /** @var string|null the generated external merchant settings ID */
90
  private $external_business_id;
91
 
109
  add_action( 'woocommerce_api_' . self::ACTION_CONNECT, [ $this, 'handle_connect' ] );
110
 
111
  add_action( 'admin_action_' . self::ACTION_DISCONNECT, [ $this, 'handle_disconnect' ] );
112
+
113
+ add_action( 'woocommerce_api_' . self::ACTION_FBE_REDIRECT, [ $this, 'handle_fbe_redirect' ] );
114
+
115
+ add_action( 'fbe_webhook', array( $this, 'fbe_install_webhook' ) );
116
+
117
+ add_action( 'rest_api_init', array( $this, 'init_extras_endpoint' ) );
118
  }
119
 
120
 
241
  if ( $response->get_ad_account_id() ) {
242
  $this->update_ad_account_id( sanitize_text_field( $response->get_ad_account_id() ) );
243
  }
244
+
245
+ if ( $response->get_instagram_business_id() ) {
246
+ $this->update_instagram_business_id( sanitize_text_field( $response->get_instagram_business_id() ) );
247
+ }
248
+
249
+ if ( $response->get_commerce_merchant_settings_id() ) {
250
+ $this->update_commerce_merchant_settings_id( sanitize_text_field( $response->get_commerce_merchant_settings_id() ) );
251
+ }
252
  }
253
 
254
 
371
  $this->update_system_user_id( '' );
372
  $this->update_business_manager_id( '' );
373
  $this->update_ad_account_id( '' );
374
+ $this->update_instagram_business_id( '' );
375
+ $this->update_commerce_merchant_settings_id( '' );
376
 
377
  update_option( \WC_Facebookcommerce_Integration::SETTING_FACEBOOK_PAGE_ID, '' );
378
  update_option( \WC_Facebookcommerce_Integration::SETTING_FACEBOOK_PIXEL_ID, '' );
601
  $scopes = [
602
  'manage_business_extension',
603
  'catalog_management',
 
604
  'ads_management',
605
  'ads_read',
606
  'pages_read_engagement', // this scope is needed to enable order management if using the Commerce feature
607
+ 'instagram_basic',
608
  ];
609
 
610
  /**
753
  }
754
 
755
 
756
+ /**
757
+ * Gets Instagram Business ID value.
758
+ *
759
+ * @since 2.3.0
760
+ *
761
+ * @return string
762
+ */
763
+ public function get_instagram_business_id() {
764
+
765
+ return get_option( self::OPTION_INSTAGRAM_BUSINESS_ID, '' );
766
+ }
767
+
768
+
769
+ /**
770
+ * Gets Commerce merchant settings ID value.
771
+ *
772
+ * @since 2.3.0
773
+ *
774
+ * @return string
775
+ */
776
+ public function get_commerce_merchant_settings_id() {
777
+
778
+ return get_option( self::OPTION_COMMERCE_MERCHANT_SETTINGS_ID, '' );
779
+ }
780
+
781
+
782
  /**
783
  * Gets the proxy URL.
784
  *
799
  }
800
 
801
 
802
+ /**
803
+ * Gets APP Store Login URL.
804
+ *
805
+ * @since 2.3.0
806
+ *
807
+ * @return string URL
808
+ */
809
+ public function get_app_store_login_url() {
810
+
811
+ /**
812
+ * Filters App Store login URL.
813
+ *
814
+ * @since 2.3.0
815
+ *
816
+ * @param string $app_store_login_url the connection App Store login URL
817
+ */
818
+ return (string) apply_filters( 'wc_facebook_connection_app_store_login_url', self::APP_STORE_LOGIN_URL );
819
+ }
820
+
821
+
822
  /**
823
  * Gets the full redirect URL where the user will return to after OAuth.
824
  *
832
  'wc-api' => self::ACTION_CONNECT,
833
  'external_business_id' => $this->get_external_business_id(),
834
  'nonce' => wp_create_nonce( self::ACTION_CONNECT ),
835
+ 'type' => self::AUTH_TYPE_STANDARD,
836
  ], home_url( '/' ) );
837
 
838
  /**
899
  'timezone' => $this->get_timezone_string(),
900
  'currency' => get_woocommerce_currency(),
901
  'business_vertical' => 'ECOMMERCE',
902
+ 'domain' => home_url(),
903
+ 'channel' => 'COMMERCE_OFFSITE',
904
  ],
905
  'business_config' => [
906
  'business' => [
1003
  }
1004
 
1005
 
1006
+ /**
1007
+ * Stores the given Instagram Business ID.
1008
+ *
1009
+ * @since 2.3.0
1010
+ *
1011
+ * @param string $id the ID
1012
+ */
1013
+ public function update_instagram_business_id( $id ) {
1014
+
1015
+ update_option( self::OPTION_INSTAGRAM_BUSINESS_ID, $id );
1016
+ }
1017
+
1018
+
1019
+ /**
1020
+ * Stores the given Commerce merchant settings ID.
1021
+ *
1022
+ * @since 2.3.0
1023
+ *
1024
+ * @param string $id the ID
1025
+ */
1026
+ public function update_commerce_merchant_settings_id( $id ) {
1027
+
1028
+ update_option( self::OPTION_COMMERCE_MERCHANT_SETTINGS_ID, $id );
1029
+ }
1030
+
1031
+
1032
  /**
1033
  * Stores the given token value.
1034
  *
1144
  }
1145
 
1146
 
1147
+ /**
1148
+ * Process WebHook User object, install field
1149
+ *
1150
+ * @since 2.3.0
1151
+ * @link https://developers.facebook.com/docs/marketing-api/fbe/fbe2/guides/get-features#webhook
1152
+ *
1153
+ * @param object $data WebHook event data.
1154
+ */
1155
+ public function fbe_install_webhook( $data ) {
1156
+
1157
+ // Reject other objects other than subscribed object
1158
+ if ( empty( $data ) || ! isset( $data->object ) || self::WEBHOOK_SUBSCRIBED_OBJECT !== $data->object ) {
1159
+
1160
+ if ( $this->get_plugin()->get_integration()->is_debug_mode_enabled() ) {
1161
+ $this->get_plugin()->log( 'Wrong (or empty) WebHook Event received' );
1162
+ $this->get_plugin()->log( print_r( $data, true ) ); //phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
1163
+ }
1164
+
1165
+ return;
1166
+ }
1167
+
1168
+ $log_data = array();
1169
+ if ( $this->get_plugin()->get_integration()->is_debug_mode_enabled() ) {
1170
+ $this->get_plugin()->log( 'WebHook User Event received' );
1171
+ $this->get_plugin()->log( print_r( $data, true ) ); //phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
1172
+ }
1173
+
1174
+ $entry = (array) $data->entry[0];
1175
+ if ( empty( $entry ) ) {
1176
+ return;
1177
+ }
1178
+
1179
+ // Filter event by subscribed field
1180
+ $event = array_filter(
1181
+ $entry['changes'],
1182
+ function( $change ) {
1183
+ return self::WEBHOOK_SUBSCRIBED_FIELD === $change->field;
1184
+ }
1185
+ );
1186
+
1187
+ $values = ! empty( $event[0] ) ? $event[0]->value : '';
1188
+ if ( empty( $values ) ) {
1189
+ return;
1190
+ }
1191
+
1192
+ /**
1193
+ * If profiles, pages and instagram_profiles fields are not included in the Webhook payload, this means the business has uninstalled FBE.
1194
+ * In this case also the field access_token will not be included.
1195
+ *
1196
+ * @link https://developers.facebook.com/docs/marketing-api/fbe/fbe2/guides/get-features#what-s-included-with-webhooks-
1197
+ */
1198
+ if ( empty( $values->access_token ) ) {
1199
+
1200
+ delete_option( 'wc_facebook_has_connected_fbe_2' );
1201
+ delete_option( 'wc_facebook_has_authorized_pages_read_engagement' );
1202
+
1203
+ $this->disconnect();
1204
+
1205
+ return;
1206
+ }
1207
+
1208
+ update_option( 'wc_facebook_has_connected_fbe_2', 'yes' );
1209
+ update_option( 'wc_facebook_has_authorized_pages_read_engagement', 'yes' );
1210
+
1211
+ $system_user_access_token = ! empty( $values->access_token ) ? sanitize_text_field( $values->access_token ) : '';
1212
+ $this->update_access_token( $system_user_access_token );
1213
+ $log_data[ self::OPTION_ACCESS_TOKEN ] = 'Token was saved';
1214
+
1215
+ if ( ! empty( $entry['uid'] ) ) {
1216
+ $this->update_system_user_id( sanitize_text_field( $entry['uid'] ) );
1217
+ $log_data[ self::OPTION_SYSTEM_USER_ID ] = sanitize_text_field( $entry['uid'] );
1218
+ }
1219
+
1220
+ $merchant_access_token = ! empty( $values->merchant_access_token ) ? sanitize_text_field( $values->merchant_access_token ) : '';
1221
+ $this->update_merchant_access_token( $merchant_access_token );
1222
+ $log_data[ self::OPTION_MERCHANT_ACCESS_TOKEN ] = 'Token was saved';
1223
+
1224
+ if ( ! empty( $values->install_time ) ) {
1225
+ update_option( \WC_Facebookcommerce_Integration::OPTION_PIXEL_INSTALL_TIME, sanitize_text_field( $values->install_time ) );
1226
+ $log_data[ \WC_Facebookcommerce_Integration::OPTION_PIXEL_INSTALL_TIME ] = sanitize_text_field( $values->install_time );
1227
+ }
1228
+
1229
+ if ( ! empty( $values->business_id ) ) {
1230
+ update_option( self::OPTION_EXTERNAL_BUSINESS_ID, sanitize_text_field( $values->business_id ) );
1231
+ $log_data[ self::OPTION_EXTERNAL_BUSINESS_ID ] = sanitize_text_field( $values->business_id );
1232
+ }
1233
+
1234
+ if ( ! empty( $values->pixel_id ) ) {
1235
+ update_option( \WC_Facebookcommerce_Integration::SETTING_FACEBOOK_PIXEL_ID, sanitize_text_field( $values->pixel_id ) );
1236
+ $log_data[ \WC_Facebookcommerce_Integration::SETTING_FACEBOOK_PIXEL_ID ] = sanitize_text_field( $values->pixel_id );
1237
+ }
1238
+
1239
+ if ( ! empty( $values->catalog_id ) ) {
1240
+ update_option( \WC_Facebookcommerce_Integration::OPTION_PRODUCT_CATALOG_ID, sanitize_text_field( $values->catalog_id ) );
1241
+ $log_data[ \WC_Facebookcommerce_Integration::OPTION_PRODUCT_CATALOG_ID ] = sanitize_text_field( $values->catalog_id );
1242
+ }
1243
+
1244
+ if ( ! empty( $values->business_manager_id ) ) {
1245
+ $this->update_business_manager_id( sanitize_text_field( $values->business_manager_id ) );
1246
+ $log_data[ self::OPTION_BUSINESS_MANAGER_ID ] = sanitize_text_field( $values->business_manager_id );
1247
+ }
1248
+
1249
+ if ( ! empty( $values->ad_account_id ) ) {
1250
+ $this->update_ad_account_id( sanitize_text_field( $values->ad_account_id ) );
1251
+ $log_data[ self::OPTION_AD_ACCOUNT_ID ] = sanitize_text_field( $values->ad_account_id );
1252
+ }
1253
+
1254
+ if ( ! empty( $values->instagram_profiles ) ) {
1255
+
1256
+ $instagram_business_id = current( $values->instagram_profiles );
1257
+
1258
+ $this->update_instagram_business_id( sanitize_text_field( $instagram_business_id ) );
1259
+ $log_data[ self::OPTION_INSTAGRAM_BUSINESS_ID ] = sanitize_text_field( $instagram_business_id );
1260
+ }
1261
+
1262
+ if ( ! empty( $values->commerce_merchant_settings_id ) ) {
1263
+ $this->update_commerce_merchant_settings_id( sanitize_text_field( $values->commerce_merchant_settings_id ) );
1264
+ $log_data[ self::OPTION_COMMERCE_MERCHANT_SETTINGS_ID ] = sanitize_text_field( $values->commerce_merchant_settings_id );
1265
+ }
1266
+
1267
+ if ( ! empty( $values->pages ) ) {
1268
+
1269
+ $page_id = current( $values->pages );
1270
+
1271
+ try {
1272
+
1273
+ update_option( \WC_Facebookcommerce_Integration::SETTING_FACEBOOK_PAGE_ID, sanitize_text_field( $page_id ) );
1274
+ $log_data[ \WC_Facebookcommerce_Integration::SETTING_FACEBOOK_PAGE_ID ] = sanitize_text_field( $page_id );
1275
+
1276
+ // get and store a current access token for the configured page
1277
+ $page_access_token = $this->retrieve_page_access_token( $page_id );
1278
+
1279
+ $this->update_page_access_token( $page_access_token );
1280
+ $log_data[ self::OPTION_PAGE_ACCESS_TOKEN ] = sanitize_text_field( $page_access_token );
1281
+
1282
+ } catch ( \Exception $e ) {
1283
+
1284
+ if ( $this->get_plugin()->get_integration()->is_debug_mode_enabled() ) {
1285
+ $this->get_plugin()->log( 'Could not request Page Token: ' . $e->getMessage() );
1286
+ }
1287
+ }
1288
+ }//end if
1289
+
1290
+ if ( $this->get_plugin()->get_integration()->is_debug_mode_enabled() ) {
1291
+ $this->get_plugin()->log( 'WebHook User event saved data' );
1292
+ $this->get_plugin()->log( print_r( $log_data, true ) ); //phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
1293
+ }
1294
+ }
1295
+
1296
+
1297
+ /**
1298
+ * Register Extras REST API endpoint
1299
+ *
1300
+ * @since 2.3.0
1301
+ */
1302
+ public function init_extras_endpoint() {
1303
+
1304
+ register_rest_route(
1305
+ 'wc-facebook/v1',
1306
+ 'extras',
1307
+ array(
1308
+ array(
1309
+ 'methods' => array( 'GET', 'POST' ),
1310
+ 'callback' => array( $this, 'extras_callback' ),
1311
+ 'permission_callback' => array( $this, 'extras_permission_callback' ),
1312
+ ),
1313
+ )
1314
+ );
1315
+ }
1316
+
1317
+
1318
+ /**
1319
+ * FBE Extras endpoint permissions
1320
+ *
1321
+ * @since 2.3.0
1322
+ *
1323
+ * @return boolean
1324
+ */
1325
+ public function extras_permission_callback() {
1326
+
1327
+ return current_user_can( 'manage_woocommerce' );
1328
+ }
1329
+
1330
+
1331
+ /**
1332
+ * Return FBE extras
1333
+ *
1334
+ * @since 2.3.0
1335
+ *
1336
+ * @return \WP_REST_Response
1337
+ */
1338
+ public function extras_callback() {
1339
+
1340
+ $extras = $this->get_connect_parameters_extras();
1341
+ if ( empty( $extras ) ) {
1342
+ return new \WP_REST_Response( null, 204 );
1343
+ }
1344
+
1345
+ return new \WP_REST_Response( $extras, 200 );
1346
+ }
1347
+
1348
+
1349
+ /**
1350
+ * Process FBE App Store login flow redirection
1351
+ *
1352
+ * @since 2.3.0
1353
+ */
1354
+ public function handle_fbe_redirect() {
1355
+
1356
+ if ( ! current_user_can( 'manage_woocommerce' ) ) {
1357
+ wp_die( esc_html__( 'You do not have permission to finish App Store login.', 'facebook-for-woocommerce' ) );
1358
+ }
1359
+
1360
+ $redirect_uri = base64_decode( $_REQUEST['redirect_uri'] ); //phpcs:ignore
1361
+
1362
+ // To ensure that we are not sharing any user data with other parties, only redirect to the redirect_uri if it matches the regular expression
1363
+ if ( empty( $redirect_uri ) || ! preg_match( '/https?:\/\/(www\.|m\.|l\.)?(\d{5}\.od\.)?(facebook|instagram|whatsapp)\.com(\/.*)?/', explode( '?', $redirect_uri )[0] ) ) {
1364
+ wp_safe_redirect( site_url() );
1365
+ exit;
1366
+ }
1367
+
1368
+ if ( empty( $_REQUEST['success'] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
1369
+
1370
+ $url_params = [
1371
+ 'store_url' => '',
1372
+ 'redirect_uri' => rawurlencode( $redirect_uri ),
1373
+ 'errors' => [ 'You need to grant access to WooCommerce.' ],
1374
+ ];
1375
+
1376
+ $redirect_url = add_query_arg(
1377
+ $url_params,
1378
+ $this->get_app_store_login_url()
1379
+ );
1380
+
1381
+ } else {
1382
+
1383
+ $redirect_url = $redirect_uri . '&extras=' . rawurlencode_deep( wp_json_encode( $this->get_connect_parameters_extras() ) );
1384
+ }
1385
+
1386
+ wp_redirect( $redirect_url ); //phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
1387
+ exit;
1388
+ }
1389
  }
includes/Handlers/WebHook.php ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
4
+ *
5
+ * This source code is licensed under the license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ * @package FacebookCommerce
9
+ */
10
+
11
+ namespace SkyVerge\WooCommerce\Facebook\Handlers;
12
+
13
+ use SkyVerge\WooCommerce\PluginFramework\v5_5_4\SV_WC_API_Exception;
14
+ use SkyVerge\WooCommerce\PluginFramework\v5_5_4\SV_WC_Helper;
15
+
16
+ defined( 'ABSPATH' ) or exit;
17
+
18
+ /**
19
+ * The WebHook handler.
20
+ *
21
+ * @since 2.3.0
22
+ */
23
+ class WebHook {
24
+
25
+ /** @var string auth page ID */
26
+ const WEBHOOK_PAGE_ID = 'wc-facebook-webhook';
27
+
28
+ /**
29
+ * Constructs a new WebHook.
30
+ *
31
+ * @param \WC_Facebookcommerce $plugin Plugin instance.
32
+ *
33
+ * @since 2.3.0
34
+ */
35
+ public function __construct( \WC_Facebookcommerce $plugin ) {
36
+
37
+ add_action( 'rest_api_init', array( $this, 'init_webhook_endpoint' ) );
38
+ }
39
+
40
+
41
+ /**
42
+ * Register WebHook REST API endpoint
43
+ *
44
+ * @since 2.3.0
45
+ */
46
+ public function init_webhook_endpoint() {
47
+
48
+ register_rest_route(
49
+ 'wc-facebook/v1',
50
+ 'webhook',
51
+ array(
52
+ array(
53
+ 'methods' => array( 'GET', 'POST' ),
54
+ 'callback' => array( $this, 'webhook_callback' ),
55
+ 'permission_callback' => array( $this, 'permission_callback' ),
56
+ ),
57
+ )
58
+ );
59
+ }
60
+
61
+
62
+ /**
63
+ * Endpoint permissions
64
+ * Woo Connect Bridge is sending the WebHook request using generated key.
65
+ *
66
+ * @since 2.3.0
67
+ *
68
+ * @return boolean
69
+ */
70
+ public function permission_callback() {
71
+
72
+ return current_user_can( 'manage_woocommerce' );
73
+ }
74
+
75
+
76
+ /**
77
+ * WebHook Listener
78
+ *
79
+ * @since 2.3.0
80
+ * @see SkyVerge\WooCommerce\Facebook\Handlers\Connection
81
+ *
82
+ * @param \WP_REST_Request $request The request.
83
+ * @return \WP_REST_Response
84
+ */
85
+ public function webhook_callback( \WP_REST_Request $request ) {
86
+
87
+ $request_body = json_decode( $request->get_body() );
88
+
89
+ if ( empty( $request_body ) ) {
90
+ return new \WP_REST_Response( null, 204 );
91
+ }
92
+
93
+ do_action( 'fbe_webhook', $request_body );
94
+
95
+ return new \WP_REST_Response( null, 200 );
96
+ }
97
+ }
includes/ProductSets/Sync.php ADDED
@@ -0,0 +1,441 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
4
+ *
5
+ * This source code is licensed under the license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ * @package FacebookCommerce
9
+ */
10
+
11
+ namespace SkyVerge\WooCommerce\Facebook\ProductSets;
12
+
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+ /**
18
+ * The product set sync handler.
19
+ *
20
+ * @since 2.3.0
21
+ */
22
+ class Sync {
23
+
24
+
25
+ /**
26
+ * Update action name
27
+ *
28
+ * @var string
29
+ */
30
+ const ACTION_UPDATE = 'UPDATE';
31
+
32
+ /**
33
+ * Delete action name
34
+ *
35
+ * @var string
36
+ */
37
+ const ACTION_DELETE = 'DELETE';
38
+
39
+ /**
40
+ * Requests array for sync schedule
41
+ *
42
+ * @var array
43
+ */
44
+ protected $requests = array();
45
+
46
+ /**
47
+ * Product's Category Previous List
48
+ *
49
+ * @since 2.3.0
50
+ *
51
+ * @var array
52
+ */
53
+ protected static $prev_product_cat = array();
54
+
55
+ /**
56
+ * Product's Category New List
57
+ *
58
+ * @since 2.3.0
59
+ *
60
+ * @var array
61
+ */
62
+ protected static $new_product_cat = array();
63
+
64
+ /**
65
+ * Product's Product Set Previous List
66
+ *
67
+ * @since 2.3.0
68
+ *
69
+ * @var array
70
+ */
71
+ protected static $prev_product_set = array();
72
+
73
+ /**
74
+ * Product's Product Set New List
75
+ *
76
+ * @since 2.3.0
77
+ *
78
+ * @var array
79
+ */
80
+ protected static $new_product_set = array();
81
+
82
+ /**
83
+ * Categories field name
84
+ *
85
+ * @since 2.3.0
86
+ *
87
+ * @var string
88
+ */
89
+ protected $categories_field = '';
90
+
91
+
92
+ /**
93
+ * Sync constructor.
94
+ *
95
+ * @since 2.3.0
96
+ */
97
+ public function __construct() {
98
+
99
+ $this->categories_field = \WC_Facebookcommerce::PRODUCT_SET_META;
100
+
101
+ $this->add_hooks();
102
+ }
103
+
104
+
105
+ /**
106
+ * Adds needed hooks to support product set sync.
107
+ *
108
+ * @since 2.3.0
109
+ */
110
+ public function add_hooks() {
111
+
112
+ // product hooks, compare taxonomies the lists before and after saving product to see if must sync
113
+ add_filter( 'wp_insert_post_data', array( $this, 'check_product_data_before_save' ), 99, 2 );
114
+ add_action( 'save_post', array( $this, 'check_product_data_after_save' ), 99, 2 );
115
+
116
+ // product hooks, sync product's product set when deleting or restoring product
117
+ add_action( 'trashed_post', array( $this, 'sync_product_product_sets' ), 99 );
118
+ add_action( 'before_delete_post', array( $this, 'sync_product_product_sets' ), 99 );
119
+ add_action( 'untrashed_post', array( $this, 'sync_product_product_sets' ), 99 );
120
+
121
+ // product set hooks, compare taxonomies the lists before and after saving product to see if must sync
122
+ add_action( 'created_fb_product_set', array( $this, 'fb_product_set_hook_before' ), 1 );
123
+ add_action( 'created_fb_product_set', array( $this, 'fb_product_set_hook_after' ), 99 );
124
+ add_action( 'edited_fb_product_set', array( $this, 'fb_product_set_hook_before' ), 1 );
125
+ add_action( 'edited_fb_product_set', array( $this, 'fb_product_set_hook_after' ), 99 );
126
+
127
+ // product cat and product set delete hooks, remove or check if must remove any product set
128
+ add_action( 'pre_delete_term', array( $this, 'sync_remove_product_set' ), 1, 2 );
129
+ add_action( 'delete_product_cat', array( $this, 'maybe_sync_product_set_on_product_cat_remove' ), 99 );
130
+ }
131
+
132
+
133
+ /** Hook methods *******************************************************************************************/
134
+
135
+
136
+ /**
137
+ * Stores the list of categories and product set of a product to compare later on 'save_post' hook.
138
+ *
139
+ * @since 2.3.0
140
+ *
141
+ * @param array $data Post Data.
142
+ * @param array $post Post.
143
+ */
144
+ public function check_product_data_before_save( $data, $post ) {
145
+
146
+ // gets product's current categories IDs
147
+ if ( ! empty( $post ) && 'product' === $post['post_type'] ) {
148
+ self::$prev_product_cat = wc_get_product_cat_ids( $post['ID'] );
149
+ self::$prev_product_set = wc_get_product_term_ids( $post['ID'], 'fb_product_set' );
150
+ }
151
+
152
+ return $data;
153
+ }
154
+
155
+ /**
156
+ * Sync Product's Product Sets based on its Categories
157
+ *
158
+ * @param int $post_id Post ID.
159
+ */
160
+ public function sync_product_product_sets( $post_id ) {
161
+
162
+ if ( 'product' !== get_post_type( $post_id ) ) {
163
+ return;
164
+ }
165
+
166
+ // get product's categories and sets
167
+ $product_cats = wc_get_product_cat_ids( $post_id );
168
+ $product_sets = wc_get_product_term_ids( $post_id, 'fb_product_set' );
169
+
170
+ $this->maybe_sync_product_sets( $product_cats, $product_sets );
171
+ }
172
+
173
+
174
+ /**
175
+ * Stores the list of categories and product set of a product to compare with the previous
176
+ *
177
+ * @since 2.3.0
178
+ *
179
+ * @param int $post_id Post ID.
180
+ * @param WP_Post $post Post Object.
181
+ */
182
+ public function check_product_data_after_save( $post_id, $post = '' ) {
183
+
184
+ if ( 'product' !== $post->post_type ) {
185
+ return;
186
+ }
187
+
188
+ // gets product's new categories IDs to compare if there are differences to sync
189
+ self::$new_product_cat = wc_get_product_cat_ids( $post_id );
190
+ self::$new_product_set = wc_get_product_term_ids( $post_id, 'fb_product_set' );
191
+
192
+ // get differences
193
+ $product_cat_diffs = $this->get_all_diff( 'product_cat' );
194
+ $product_set_diffs = $this->get_all_diff( 'product_set' );
195
+ if ( ! $product_cat_diffs && ! $product_set_diffs ) {
196
+ return;
197
+ }
198
+
199
+ $this->maybe_sync_product_sets( $product_cat_diffs, $product_set_diffs );
200
+ }
201
+
202
+
203
+ /**
204
+ * Check if must sync Product Sets from given lists
205
+ *
206
+ * @since 2.3.0
207
+ *
208
+ * @param array $product_cats Product Category Term IDs.
209
+ * @param array $product_sets Product Set Term IDs.
210
+ */
211
+ public function maybe_sync_product_sets( $product_cats, $product_sets ) {
212
+
213
+ if ( empty( $product_sets ) || ! is_array( $product_sets ) ) {
214
+ $product_sets = array();
215
+ }
216
+ $product_set_term_ids = array_merge( array(), $product_sets );
217
+
218
+ // check if product cat belongs to a product_set
219
+ foreach ( $product_cats as $product_cat_id ) {
220
+
221
+ $cat_product_sets = $this->get_product_cat_sets( $product_cat_id );
222
+ if ( ! empty( $cat_product_sets ) ) {
223
+ $product_set_term_ids = array_merge( $product_set_term_ids, $cat_product_sets );
224
+ }
225
+ }
226
+
227
+ foreach ( $product_set_term_ids as $product_set_id ) {
228
+ $this->maybe_sync_product_set( $product_set_id );
229
+ }
230
+ }
231
+
232
+
233
+ /**
234
+ * Stores the list of categories of a product set to compare later.
235
+ *
236
+ * @since 2.3.0
237
+ *
238
+ * @param int $term_id Term ID.
239
+ */
240
+ public function fb_product_set_hook_before( $term_id ) {
241
+ self::$prev_product_cat = get_term_meta( $term_id, $this->categories_field, true );
242
+ }
243
+
244
+
245
+ /**
246
+ * Stores the list of categories of a product set to compare with the previous and check if must sync
247
+ *
248
+ * @since 2.3.0
249
+ *
250
+ * @param int $term_id Term ID.
251
+ */
252
+ public function fb_product_set_hook_after( $term_id ) {
253
+ self::$new_product_cat = get_term_meta( $term_id, $this->categories_field, true );
254
+ if ( ! empty( $this->get_all_diff( 'product_cat' ) ) ) {
255
+ $this->maybe_sync_product_set( $term_id );
256
+ }
257
+ }
258
+
259
+
260
+ /**
261
+ * Check if must sync Product Set from FB when removing Product Cat
262
+ *
263
+ * @since 2.3.0
264
+ *
265
+ * @param int $term_id Product Cat Term ID.
266
+ */
267
+ public function maybe_sync_product_set_on_product_cat_remove( $term_id ) {
268
+
269
+ $product_sets = $this->get_product_cat_sets( $term_id );
270
+ if ( empty( $product_sets ) ) {
271
+ return;
272
+ }
273
+
274
+ foreach ( $product_sets as $product_set_id ) {
275
+ $this->maybe_sync_product_set( $product_set_id );
276
+ }
277
+ }
278
+
279
+
280
+ /**
281
+ * Call API to remove Product Set from FB
282
+ *
283
+ * @since 2.3.0
284
+ *
285
+ * @param int $product_set_term_id Product Set Term ID.
286
+ */
287
+ public function sync_remove_product_set( $product_set_term_id, $taxonomy ) {
288
+
289
+ if ( 'fb_product_set' !== $taxonomy ) {
290
+ return;
291
+ }
292
+
293
+ // get product set FB ID
294
+ $fb_product_set_id = get_term_meta( $product_set_term_id, \WC_Facebookcommerce_Integration::FB_PRODUCT_SET_ID, true );
295
+ if ( empty( $fb_product_set_id ) ) {
296
+ return;
297
+ }
298
+
299
+ do_action( 'fb_wc_product_set_delete', $fb_product_set_id );
300
+ }
301
+
302
+
303
+ /** Utility methods *******************************************************************************************/
304
+
305
+
306
+ /**
307
+ * Maybe sync product set
308
+ *
309
+ * @since 2.3.0
310
+ *
311
+ * @param int $product_set_id FB Product Set Term ID.
312
+ */
313
+ public function maybe_sync_product_set( $product_set_id ) {
314
+
315
+ // get Product Set
316
+ $term = get_term( $product_set_id );
317
+ if ( empty( $term ) ) {
318
+ return;
319
+ }
320
+
321
+ // get categories
322
+ $product_cat_ids = get_term_meta( $product_set_id, $this->categories_field, true );
323
+
324
+ // get products for the taxonomies
325
+ $products = array();
326
+ $products_args = array(
327
+ 'fields' => 'ids',
328
+ 'post_type' => 'product',
329
+ 'post_status' => 'publish',
330
+ 'posts_per_page' => -1,
331
+ 'tax_query' => array(
332
+ 'relation' => 'OR',
333
+ array(
334
+ 'taxonomy' => 'fb_product_set',
335
+ 'field' => 'term_taxonomy_id',
336
+ 'terms' => array( $product_set_id ),
337
+ 'operator' => 'IN',
338
+ ),
339
+ array(
340
+ 'taxonomy' => 'product_cat',
341
+ 'field' => 'term_taxonomy_id',
342
+ 'terms' => $product_cat_ids,
343
+ 'operator' => 'IN',
344
+ ),
345
+ ),
346
+ );
347
+ $product_ids = get_posts( $products_args );
348
+
349
+ if ( empty( $product_ids ) ) {
350
+ $fb_product_set_id = get_term_meta( $product_set_id, \WC_Facebookcommerce_Integration::FB_PRODUCT_SET_ID, true );
351
+ update_term_meta( $product_set_id, \WC_Facebookcommerce_Integration::FB_PRODUCT_SET_ID, '' );
352
+ do_action( 'fb_wc_product_set_delete', $fb_product_set_id );
353
+ }
354
+
355
+ // gets products variations
356
+ global $wpdb;
357
+ $variation_ids = $wpdb->get_results( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = 'product_variation' AND post_parent IN (%s) ", implode( ',', $product_ids ) ) );
358
+ if ( ! empty( $variation_ids ) ) {
359
+
360
+ // product_variations: add retailer id to the products filter
361
+ foreach ( $variation_ids as $variation_id ) {
362
+
363
+ $product = new \WC_Product_Variation( $variation_id->ID );
364
+ $fb_retailer_id = \WC_Facebookcommerce_Utils::get_fb_retailer_id( $product );
365
+
366
+ array_push(
367
+ $products,
368
+ array( 'retailer_id' => array( 'eq' => $fb_retailer_id ) )
369
+ );
370
+ }
371
+ }
372
+
373
+ // products: add retailer id to the products filter
374
+ foreach ( $product_ids as $product_id ) {
375
+
376
+ $product = new \WC_Product( $product_id );
377
+ $fb_retailer_id = \WC_Facebookcommerce_Utils::get_fb_retailer_id( $product );
378
+
379
+ array_push(
380
+ $products,
381
+ array( 'retailer_id' => array( 'eq' => $fb_retailer_id ) )
382
+ );
383
+ }
384
+
385
+ $data = array(
386
+ 'name' => $term->name,
387
+ 'filter' => wp_json_encode( array( 'or' => $products ) ),
388
+ );
389
+
390
+ do_action( 'fb_wc_product_set_sync', $data, $product_set_id );
391
+ }
392
+
393
+
394
+ /**
395
+ * Return the list of product sets of a given product category term
396
+ *
397
+ * @since 2.3.0
398
+ *
399
+ * @param string $product_cat_id product cat Term ID.
400
+ *
401
+ * @return array
402
+ */
403
+ protected function get_product_cat_sets( $product_cat_id ) {
404
+
405
+ $args = array(
406
+ 'fields' => 'ids',
407
+ 'taxonomy' => 'fb_product_set',
408
+ 'hide_empty' => false,
409
+ 'meta_query' => array(
410
+ array(
411
+ 'key' => \WC_Facebookcommerce::PRODUCT_SET_META,
412
+ 'value' => sprintf( ':%d;', $product_cat_id ),
413
+ 'compare' => 'LIKE',
414
+ ),
415
+ ),
416
+ );
417
+ return get_terms( $args );
418
+ }
419
+
420
+ /**
421
+ * Return the list of differences between two list of terms
422
+ *
423
+ * @since 2.3.0
424
+ *
425
+ * @param string $taxonomy Taxonomy slug.
426
+ *
427
+ * @return array
428
+ */
429
+ protected function get_all_diff( $taxonomy = 'product_cat' ) {
430
+
431
+ $prev = empty( self::${ 'prev_' . $taxonomy } ) ? array() : self::${ 'prev_' . $taxonomy };
432
+ $new = empty( self::${ 'new_' . $taxonomy } ) ? array() : self::${ 'new_' . $taxonomy };
433
+
434
+ $removed = array_diff( $prev, $new );
435
+ $added = array_diff( $new, $prev );
436
+
437
+ return array_merge( $removed, $added );
438
+ }
439
+
440
+
441
+ }
includes/Product_Categories.php CHANGED
@@ -15,7 +15,7 @@ defined( 'ABSPATH' ) or exit;
15
  /**
16
  * Helper class with utility methods for getting and setting various product category values.
17
  *
18
- * @since 2.3.0-dev.1
19
  */
20
  class Product_Categories {
21
 
@@ -25,7 +25,7 @@ class Product_Categories {
25
  *
26
  * Does not fall back to the plugin settings.
27
  *
28
- * @since 2.3.0-dev.1
29
  *
30
  * @param int $category_id category ID
31
  * @return string
@@ -39,7 +39,7 @@ class Product_Categories {
39
  /**
40
  * Updates the stored Google product category ID for the Products::GOOGLE_PRODUCT_CATEGORY_META_KEY meta.
41
  *
42
- * @since 2.3.0-dev.1
43
  *
44
  * @param int $id category ID
45
  * @param string $category_id Google product category ID
15
  /**
16
  * Helper class with utility methods for getting and setting various product category values.
17
  *
18
+ * @since 2.2.0
19
  */
20
  class Product_Categories {
21
 
25
  *
26
  * Does not fall back to the plugin settings.
27
  *
28
+ * @since 2.2.0
29
  *
30
  * @param int $category_id category ID
31
  * @return string
39
  /**
40
  * Updates the stored Google product category ID for the Products::GOOGLE_PRODUCT_CATEGORY_META_KEY meta.
41
  *
42
+ * @since 2.2.0
43
  *
44
  * @param int $id category ID
45
  * @param string $category_id Google product category ID
includes/Products.php CHANGED
@@ -581,8 +581,14 @@ class Products {
581
  $level = 0;
582
  $parent_category = $category;
583
 
584
- while ( $parent_category->parent !== 0 ) {
 
585
  $parent_category = get_term( $parent_category->parent, 'product_cat' );
 
 
 
 
 
586
  $level ++;
587
  }
588
 
@@ -668,8 +674,14 @@ class Products {
668
  $level = 0;
669
  $parent_category = $category;
670
 
671
- while ( $parent_category->parent !== 0 ) {
 
672
  $parent_category = get_term( $parent_category->parent, 'product_cat' );
 
 
 
 
 
673
  $level ++;
674
  }
675
 
581
  $level = 0;
582
  $parent_category = $category;
583
 
584
+ while ( (int) $parent_category->parent !== 0 ) {
585
+
586
  $parent_category = get_term( $parent_category->parent, 'product_cat' );
587
+
588
+ if ( ! $parent_category instanceof \WP_Term ) {
589
+ break;
590
+ }
591
+
592
  $level ++;
593
  }
594
 
674
  $level = 0;
675
  $parent_category = $category;
676
 
677
+ while ( (int) $parent_category->parent !== 0 ) {
678
+
679
  $parent_category = get_term( $parent_category->parent, 'product_cat' );
680
+
681
+ if ( ! $parent_category instanceof \WP_Term ) {
682
+ break;
683
+ }
684
+
685
  $level ++;
686
  }
687
 
includes/fbgraph.php CHANGED
@@ -160,8 +160,8 @@ if ( ! class_exists( 'WC_Facebookcommerce_Graph_API' ) ) :
160
  'timeout' => self::CURL_TIMEOUT,
161
  ];
162
 
163
- $fbasync = new WC_Facebookcommerce_Async_Request();
164
 
 
165
  $fbasync->query_url = $url;
166
  $fbasync->query_args = array();
167
  $fbasync->post_args = $request_args;
@@ -394,6 +394,24 @@ if ( ! class_exists( 'WC_Facebookcommerce_Graph_API' ) ) :
394
  return self::_delete( $product_group_url );
395
  }
396
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
  public function log( $ems_id, $message, $error ) {
398
  $log_url = $this->build_url( $ems_id, '/log_events' );
399
 
@@ -568,10 +586,13 @@ if ( ! class_exists( 'WC_Facebookcommerce_Graph_API' ) ) :
568
  return self::_post( $url, $data );
569
  }
570
 
571
- private function build_url( $field_id, $param = '' ) {
572
- return self::GRAPH_API_URL . (string) $field_id . $param;
 
 
 
 
573
  }
574
-
575
  }
576
 
577
  endif;
160
  'timeout' => self::CURL_TIMEOUT,
161
  ];
162
 
 
163
 
164
+ $fbasync = new WC_Facebookcommerce_Async_Request();
165
  $fbasync->query_url = $url;
166
  $fbasync->query_args = array();
167
  $fbasync->post_args = $request_args;
394
  return self::_delete( $product_group_url );
395
  }
396
 
397
+ // POST https://graph.facebook.com/vX.X/{product-catalog-id}/product_sets
398
+ public function create_product_set_item( $product_catalog_id, $data ) {
399
+ $url = $this->build_url( $product_catalog_id, '/product_sets', '8.0' );
400
+ return self::_post( $url, $data );
401
+ }
402
+
403
+ // POST https://graph.facebook.com/vX.X/{product-set-id}
404
+ public function update_product_set_item( $product_set_id, $data ) {
405
+ $url = $this->build_url( $product_set_id, '', '8.0' );
406
+ return self::_post( $url, $data );
407
+ }
408
+
409
+ public function delete_product_set_item( $product_set_id ) {
410
+ $url = $this->build_url( $product_set_id, '', '8.0' );
411
+ return self::_delete( $url );
412
+ }
413
+
414
+
415
  public function log( $ems_id, $message, $error ) {
416
  $log_url = $this->build_url( $ems_id, '/log_events' );
417
 
586
  return self::_post( $url, $data );
587
  }
588
 
589
+ private function build_url( $field_id, $param = '', $api_version = '' ) {
590
+ $api_url = self::GRAPH_API_URL;
591
+ if ( ! empty( $api_version ) ) {
592
+ $api_url = str_replace( '2.9', str_replace( 'v', '', trim( $api_version ) ), $api_url );
593
+ }
594
+ return $api_url . (string) $field_id . $param;
595
  }
 
596
  }
597
 
598
  endif;
includes/fbproduct.php CHANGED
@@ -39,6 +39,7 @@ if ( ! class_exists( 'WC_Facebook_Product' ) ) :
39
  const FB_PRODUCT_IMAGE = 'fb_product_image';
40
  const FB_VARIANT_IMAGE = 'fb_image';
41
  const FB_VISIBILITY = 'fb_visibility';
 
42
 
43
  const MIN_DATE_1 = '1970-01-29';
44
  const MIN_DATE_2 = '1970-01-30';
@@ -671,11 +672,19 @@ if ( ! class_exists( 'WC_Facebook_Product' ) ) :
671
  $category = $category_handler->get_category_with_attrs( $google_category_id );
672
  $all_attributes = $category['attributes'];
673
  foreach ( $all_attributes as $attribute ) {
674
- $value = Products::get_enhanced_catalog_attribute( $attribute['key'], $this->woo_product );
 
 
 
 
 
675
 
676
  if ( ! empty( $value ) &&
677
  $category_handler->is_valid_value_for_attribute( $google_category_id, $attribute['key'], $value )
678
  ) {
 
 
 
679
  $enhanced_data[ $attribute['key'] ] = $value;
680
  }
681
  }
39
  const FB_PRODUCT_IMAGE = 'fb_product_image';
40
  const FB_VARIANT_IMAGE = 'fb_image';
41
  const FB_VISIBILITY = 'fb_visibility';
42
+ const FB_REMOVE_FROM_SYNC = 'fb_remove_from_sync';
43
 
44
  const MIN_DATE_1 = '1970-01-29';
45
  const MIN_DATE_2 = '1970-01-30';
672
  $category = $category_handler->get_category_with_attrs( $google_category_id );
673
  $all_attributes = $category['attributes'];
674
  foreach ( $all_attributes as $attribute ) {
675
+ $value = Products::get_enhanced_catalog_attribute( $attribute['key'], $this->woo_product );
676
+ $convert_to_array = (
677
+ isset( $attribute['can_have_multiple_values'] ) &&
678
+ true === $attribute['can_have_multiple_values'] &&
679
+ 'string' === $attribute['type']
680
+ );
681
 
682
  if ( ! empty( $value ) &&
683
  $category_handler->is_valid_value_for_attribute( $google_category_id, $attribute['key'], $value )
684
  ) {
685
+ if ( $convert_to_array ) {
686
+ $value = array_map( 'trim', explode( ',', $value ) );
687
+ }
688
  $enhanced_data[ $attribute['key'] ] = $value;
689
  }
690
  }
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: facebook, automattic, woothemes
3
  Tags: facebook, shop, catalog, advertise, pixel, product
4
  Requires at least: 4.4
5
- Tested up to: 5.5.3
6
- Stable tag: 2.2.0
7
  Requires PHP: 5.6 or greater
8
  MySQL: 5.6 or greater
9
  License: GPLv2 or later
@@ -39,6 +39,16 @@ When opening a bug on GitHub, please give us as many details as possible.
39
 
40
  == Changelog ==
41
 
 
 
 
 
 
 
 
 
 
 
42
  = 2020.11.19 - version 2.2.0 =
43
  * Feature - Add an Advertise tab in the Facebook settings page to manage Facebook ads from within WooCommerce
44
  * Tweak - Move the Facebook settings page into the Marketing menu item (WooCommerce 4.0+)
2
  Contributors: facebook, automattic, woothemes
3
  Tags: facebook, shop, catalog, advertise, pixel, product
4
  Requires at least: 4.4
5
+ Tested up to: 5.6
6
+ Stable tag: 2.3.0
7
  Requires PHP: 5.6 or greater
8
  MySQL: 5.6 or greater
9
  License: GPLv2 or later
39
 
40
  == Changelog ==
41
 
42
+ = 2021.02.16 - version 2.3.0 =
43
+ * Feature - Add ability to create and assign products to Facebook product sets
44
+ * Feature - Add support for Facebook App store flow
45
+ * Tweak - Ask merchants to delete products when changing from sync to not sync state
46
+ * Tweak - Remove business_management permission from login scopes
47
+ * Tweak - Store paramaters for Commerce merchant settings ID and Instagram business ID
48
+ * Fix - Fix Products::get_google_product_category_id_from_highest_category() to handle WP_Error
49
+ * Fix - Fix random HELLO appearing in the category settings
50
+ * Fix - Make sure that list of strings params are now converted to actual arrays. Fixes an issue with the use of the additional_features parameter
51
+
52
  = 2020.11.19 - version 2.2.0 =
53
  * Feature - Add an Advertise tab in the Facebook settings page to manage Facebook ads from within WooCommerce
54
  * Tweak - Move the Facebook settings page into the Marketing menu item (WooCommerce 4.0+)