Facebook for WooCommerce - Version 2.0.2

Version Description

Download this release

Release Info

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

Code changes from version 2.0.1 to 2.0.2

changelog.txt CHANGED
@@ -1,5 +1,12 @@
1
  *** Facebook for WooCommerce Changelog ***
2
 
 
 
 
 
 
 
 
3
  2020.08.17 - version 2.0.1
4
  * Fix - Ensure the configured business name is never empty when connecting to Facebook
5
 
1
  *** Facebook for WooCommerce Changelog ***
2
 
3
+ 2020.09.25 - version 2.0.2
4
+ * Tweak - Allow simple and variable products with zero/empty price to sync to Facebook
5
+ * Tweak - Use the bundle price for Product Bundles products with individually priced items
6
+ * Fix - Update connection parameters to use an array to pass the Messenger domain
7
+ * Fix - Ensure out-of-stock products are marked as such in Facebook when the feed file replacement is run
8
+ * Fix - Address a potential error when connecting from a site whose title contains special characters
9
+
10
  2020.08.17 - version 2.0.1
11
  * Fix - Ensure the configured business name is never empty when connecting to Facebook
12
 
class-wc-facebookcommerce.php CHANGED
@@ -21,7 +21,7 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
21
 
22
 
23
  /** @var string the plugin version */
24
- const VERSION = '2.0.1';
25
 
26
  /** @var string for backwards compatibility TODO: remove this in v2.0.0 {CW 2020-02-06} */
27
  const PLUGIN_VERSION = self::VERSION;
21
 
22
 
23
  /** @var string the plugin version */
24
+ const VERSION = '2.0.2';
25
 
26
  /** @var string for backwards compatibility TODO: remove this in v2.0.0 {CW 2020-02-06} */
27
  const PLUGIN_VERSION = self::VERSION;
facebook-commerce.php CHANGED
@@ -572,11 +572,11 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
572
  global $post;
573
 
574
  $woo_product = new WC_Facebook_Product( $post->ID );
575
- $fb_product_group_id = $this->get_product_fbid(
576
- self::FB_PRODUCT_GROUP_ID,
577
- $post->ID,
578
- $woo_product
579
- );
580
 
581
  ?>
582
  <span id="fb_metadata">
@@ -896,6 +896,7 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
896
  case 'simple':
897
  case 'booking':
898
  case 'external':
 
899
  $this->on_simple_product_publish( $wp_id );
900
  break;
901
 
@@ -964,7 +965,7 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
964
  * @see ajax_delete_fb_product()
965
  */
966
  if ( ( ! is_ajax() || ! isset( $_POST['action'] ) || 'ajax_delete_fb_product' !== $_POST['action'] )
967
- && ! Products::product_should_be_synced( $product ) ) {
968
 
969
  return;
970
  }
@@ -1017,6 +1018,10 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
1017
  return;
1018
  }
1019
 
 
 
 
 
1020
  $visibility = $new_status === 'publish' ? self::FB_SHOP_PRODUCT_VISIBLE : self::FB_SHOP_PRODUCT_HIDDEN;
1021
 
1022
  $product = wc_get_product( $post->ID );
@@ -1027,16 +1032,30 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
1027
  // variations before it gets called with the variable product. As a result, Products::product_should_be_synced()
1028
  // always returns false for the variable product (since all children are in the trash at that point).
1029
  // This causes update_fb_visibility() to be called on simple products and product variations only.
1030
- if ( ! $product instanceof \WC_Product || ! Products::product_should_be_synced( $product ) ) {
1031
  return;
1032
  }
1033
 
1034
- // change from publish status -> unpublish status (e.g. trash, draft, etc.)
1035
- // change from trash status -> publish status
1036
- // no need to update for change from trash <-> unpublish status
1037
- if ( ( $old_status === 'publish' && $new_status !== 'publish' ) || ( $old_status === 'trash' && $new_status === 'publish' ) ) {
1038
- $this->update_fb_visibility( $product, $visibility );
1039
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1040
  }
1041
 
1042
 
@@ -1209,30 +1228,19 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
1209
  /**
1210
  * Determines whether the product with the given ID should be synced.
1211
  *
1212
- * TODO: can we move this logic into Products::product_should_be_synced()? {WV 2020-05-22}
1213
- *
1214
  * @since 2.0.0
1215
  *
1216
  * @param \WC_Product|false $product product object
1217
  */
1218
  public function product_should_be_synced( $product ) {
1219
 
1220
- $should_be_synced = true;
1221
-
1222
- if ( ! $this->is_product_sync_enabled() ) {
1223
- $should_be_synced = false;
1224
- }
1225
 
1226
  // can't sync if we don't have a valid product object
1227
  if ( $should_be_synced && ! $product instanceof \WC_Product ) {
1228
  $should_be_synced = false;
1229
  }
1230
 
1231
- // only published product should be synced
1232
- if ( $should_be_synced && 'publish' !== get_post_status( $product->get_id() ) ) {
1233
- $should_be_synced = false;
1234
- }
1235
-
1236
  // make sure the given product is enabled for sync
1237
  if ( $should_be_synced && ! Products::product_should_be_synced( $product ) ) {
1238
  $should_be_synced = false;
@@ -1310,10 +1318,7 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
1310
 
1311
  function create_product_item( $woo_product, $retailer_id, $product_group_id ) {
1312
 
1313
- $product_data = $woo_product->prepare_product( $retailer_id );
1314
- if ( ! $product_data['price'] ) {
1315
- return 0;
1316
- }
1317
 
1318
  $product_result = $this->check_api_result(
1319
  $this->fbgraph->create_product_item(
@@ -3337,7 +3342,7 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
3337
  public function on_quick_and_bulk_edit_save( $product ) {
3338
 
3339
  // bail if not a product or product is not enabled for sync
3340
- if ( ! $product instanceof \WC_Product || ! Products::product_should_be_synced( $product ) ) {
3341
  return;
3342
  }
3343
 
@@ -3383,12 +3388,6 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
3383
  // if the product with ID equal to $wp_id is variable, $woo_product will be the first child
3384
  $woo_product = new WC_Facebook_Product( current( $products ) );
3385
 
3386
- // This is a generalized function used elsewhere
3387
- // Cannot call is_hidden for VC_Product_Variable Object
3388
- if ( $woo_product->is_hidden() ) {
3389
- return null;
3390
- }
3391
-
3392
  $fb_retailer_id = WC_Facebookcommerce_Utils::get_fb_retailer_id( $woo_product );
3393
 
3394
  $product_fbid_result = $this->fbgraph->get_facebook_id(
572
  global $post;
573
 
574
  $woo_product = new WC_Facebook_Product( $post->ID );
575
+ $fb_product_group_id = null;
576
+
577
+ if ( $woo_product->woo_product instanceof \WC_Product && Products::product_should_be_synced( $woo_product->woo_product ) ) {
578
+ $fb_product_group_id = $this->get_product_fbid( self::FB_PRODUCT_GROUP_ID, $post->ID, $woo_product );
579
+ }
580
 
581
  ?>
582
  <span id="fb_metadata">
896
  case 'simple':
897
  case 'booking':
898
  case 'external':
899
+ case 'composite':
900
  $this->on_simple_product_publish( $wp_id );
901
  break;
902
 
965
  * @see ajax_delete_fb_product()
966
  */
967
  if ( ( ! is_ajax() || ! isset( $_POST['action'] ) || 'ajax_delete_fb_product' !== $_POST['action'] )
968
+ && ! Products::published_product_should_be_synced( $product ) ) {
969
 
970
  return;
971
  }
1018
  return;
1019
  }
1020
 
1021
+ if ( ! $this->should_update_visibility_for_product_status_change( $new_status, $old_status ) ) {
1022
+ return;
1023
+ }
1024
+
1025
  $visibility = $new_status === 'publish' ? self::FB_SHOP_PRODUCT_VISIBLE : self::FB_SHOP_PRODUCT_HIDDEN;
1026
 
1027
  $product = wc_get_product( $post->ID );
1032
  // variations before it gets called with the variable product. As a result, Products::product_should_be_synced()
1033
  // always returns false for the variable product (since all children are in the trash at that point).
1034
  // This causes update_fb_visibility() to be called on simple products and product variations only.
1035
+ if ( ! $product instanceof \WC_Product || ! Products::published_product_should_be_synced( $product ) ) {
1036
  return;
1037
  }
1038
 
1039
+ $this->update_fb_visibility( $product, $visibility );
1040
+ }
1041
+
1042
+
1043
+ /**
1044
+ * Determines whether the product visibility needs to be updated for the given status change.
1045
+ *
1046
+ * Change from publish status -> unpublish status (e.g. trash, draft, etc.)
1047
+ * Change from trash status -> publish status
1048
+ * No need to update for change from trash <-> unpublish status
1049
+ *
1050
+ * @since 2.0.2
1051
+ *
1052
+ * @param string $new_status
1053
+ * @param string $old_status
1054
+ * @return bool
1055
+ */
1056
+ private function should_update_visibility_for_product_status_change( $new_status, $old_status ) {
1057
+
1058
+ return ( $old_status === 'publish' && $new_status !== 'publish' ) || ( $old_status === 'trash' && $new_status === 'publish' );
1059
  }
1060
 
1061
 
1228
  /**
1229
  * Determines whether the product with the given ID should be synced.
1230
  *
 
 
1231
  * @since 2.0.0
1232
  *
1233
  * @param \WC_Product|false $product product object
1234
  */
1235
  public function product_should_be_synced( $product ) {
1236
 
1237
+ $should_be_synced = $this->is_product_sync_enabled();
 
 
 
 
1238
 
1239
  // can't sync if we don't have a valid product object
1240
  if ( $should_be_synced && ! $product instanceof \WC_Product ) {
1241
  $should_be_synced = false;
1242
  }
1243
 
 
 
 
 
 
1244
  // make sure the given product is enabled for sync
1245
  if ( $should_be_synced && ! Products::product_should_be_synced( $product ) ) {
1246
  $should_be_synced = false;
1318
 
1319
  function create_product_item( $woo_product, $retailer_id, $product_group_id ) {
1320
 
1321
+ $product_data = $woo_product->prepare_product( $retailer_id );
 
 
 
1322
 
1323
  $product_result = $this->check_api_result(
1324
  $this->fbgraph->create_product_item(
3342
  public function on_quick_and_bulk_edit_save( $product ) {
3343
 
3344
  // bail if not a product or product is not enabled for sync
3345
+ if ( ! $product instanceof \WC_Product || ! Products::published_product_should_be_synced( $product ) ) {
3346
  return;
3347
  }
3348
 
3388
  // if the product with ID equal to $wp_id is variable, $woo_product will be the first child
3389
  $woo_product = new WC_Facebook_Product( current( $products ) );
3390
 
 
 
 
 
 
 
3391
  $fb_retailer_id = WC_Facebookcommerce_Utils::get_fb_retailer_id( $woo_product );
3392
 
3393
  $product_fbid_result = $this->fbgraph->get_facebook_id(
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.0.1
14
  * Text Domain: facebook-for-woocommerce
15
  * WC requires at least: 3.5.0
16
- * WC tested up to: 4.3.3
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.0.2
14
  * Text Domain: facebook-for-woocommerce
15
  * WC requires at least: 3.5.0
16
+ * WC tested up to: 4.5.2
17
  *
18
  * @package FacebookCommerce
19
  */
i18n/languages/facebook-for-woocommerce.pot CHANGED
@@ -2,10 +2,10 @@
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.0.1\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://woocommerce.com/my-account/marketplace-ticket-form/\n"
8
- "POT-Creation-Date: 2020-08-17 20:20:42+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
@@ -87,45 +87,45 @@ msgstr ""
87
  msgid "This product is not yet synced to Facebook."
88
  msgstr ""
89
 
90
- #: facebook-commerce.php:1369
91
  msgid "Nothing to update for product group for %1$s"
92
  msgstr ""
93
 
94
- #: facebook-commerce.php:1635
95
  #. translators: Placeholders %1$s - original error message from Facebook API
96
  msgid "There was an issue connecting to the Facebook API: %1$s"
97
  msgstr ""
98
 
99
- #: facebook-commerce.php:1972
100
  msgid "Your connection has expired."
101
  msgstr ""
102
 
103
- #: facebook-commerce.php:1972
104
  msgid ""
105
  "Please click Manage connection > Advanced Options > Update Token to refresh "
106
  "your connection to Facebook."
107
  msgstr ""
108
 
109
- #: facebook-commerce.php:1979
110
  #. translators: Placeholders %s - error message
111
  msgid "There was an error trying to sync the products to Facebook. %s"
112
  msgstr ""
113
 
114
- #: facebook-commerce.php:2002 facebook-commerce.php:2175
115
  msgid "Product sync is disabled."
116
  msgstr ""
117
 
118
- #: facebook-commerce.php:2009 facebook-commerce.php:2182
119
  msgid "The plugin is not configured or the Catalog ID is missing."
120
  msgstr ""
121
 
122
- #: facebook-commerce.php:2032
123
  msgid ""
124
  "A product sync is in progress. Please wait until the sync finishes before "
125
  "starting a new one."
126
  msgstr ""
127
 
128
- #: facebook-commerce.php:2044 facebook-commerce.php:2196
129
  msgid ""
130
  "We've detected that your Facebook Product Catalog is no longer valid. This "
131
  "may happen if it was deleted, but could also be a temporary error. If the "
@@ -133,33 +133,33 @@ msgid ""
133
  "and setup the plugin again."
134
  msgstr ""
135
 
136
- #: facebook-commerce.php:2220
137
  msgid "We couldn't create the feed or upload the product information."
138
  msgstr ""
139
 
140
- #: facebook-commerce.php:2687
141
  msgid "Hi! We're here to answer any questions you may have."
142
  msgstr ""
143
 
144
- #: facebook-commerce.php:3031
145
  msgid "Facebook for WooCommerce error:"
146
  msgstr ""
147
 
148
- #: facebook-commerce.php:3113
149
  msgid ""
150
  "There was an error trying to retrieve information about the Facebook page: "
151
  "%s"
152
  msgstr ""
153
 
154
- #: facebook-commerce.php:3164
155
  msgid "Get started with Messenger Customer Chat"
156
  msgstr ""
157
 
158
- #: facebook-commerce.php:3165
159
  msgid "Get started with Instagram Shopping"
160
  msgstr ""
161
 
162
- #: facebook-commerce.php:3406
163
  #. translators: Placeholders %1$s - original error message from Facebook API
164
  msgid "There was an issue connecting to the Facebook API: %s"
165
  msgstr ""
@@ -608,15 +608,15 @@ msgstr ""
608
  msgid "Uninstall unsuccessful. Please try again."
609
  msgstr ""
610
 
611
- #: includes/Products/Sync/Background.php:64
612
  msgid "Job data key \"%s\" not set"
613
  msgstr ""
614
 
615
- #: includes/Products/Sync/Background.php:68
616
  msgid "Job data key \"%s\" is not an array"
617
  msgstr ""
618
 
619
- #: includes/Products/Sync/Background.php:150
620
  msgid ""
621
  "There was an error trying sync products using the Catalog Batch API for job "
622
  "%s: %s"
@@ -638,19 +638,19 @@ msgstr ""
638
  msgid "Dismiss"
639
  msgstr ""
640
 
641
- #: includes/fbproductfeed.php:483
642
  msgid "Could not create product catalog feed directory"
643
  msgstr ""
644
 
645
- #: includes/fbproductfeed.php:549
646
  msgid "Could not open the product catalog temporary feed file for writing"
647
  msgstr ""
648
 
649
- #: includes/fbproductfeed.php:556
650
  msgid "Could not open the product catalog feed file for writing"
651
  msgstr ""
652
 
653
- #: includes/fbproductfeed.php:603
654
  msgid "Could not rename the product catalog feed file"
655
  msgstr ""
656
 
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.0.2\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://woocommerce.com/my-account/marketplace-ticket-form/\n"
8
+ "POT-Creation-Date: 2020-09-26 00:08:41+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
87
  msgid "This product is not yet synced to Facebook."
88
  msgstr ""
89
 
90
+ #: facebook-commerce.php:1374
91
  msgid "Nothing to update for product group for %1$s"
92
  msgstr ""
93
 
94
+ #: facebook-commerce.php:1640
95
  #. translators: Placeholders %1$s - original error message from Facebook API
96
  msgid "There was an issue connecting to the Facebook API: %1$s"
97
  msgstr ""
98
 
99
+ #: facebook-commerce.php:1977
100
  msgid "Your connection has expired."
101
  msgstr ""
102
 
103
+ #: facebook-commerce.php:1977
104
  msgid ""
105
  "Please click Manage connection > Advanced Options > Update Token to refresh "
106
  "your connection to Facebook."
107
  msgstr ""
108
 
109
+ #: facebook-commerce.php:1984
110
  #. translators: Placeholders %s - error message
111
  msgid "There was an error trying to sync the products to Facebook. %s"
112
  msgstr ""
113
 
114
+ #: facebook-commerce.php:2007 facebook-commerce.php:2180
115
  msgid "Product sync is disabled."
116
  msgstr ""
117
 
118
+ #: facebook-commerce.php:2014 facebook-commerce.php:2187
119
  msgid "The plugin is not configured or the Catalog ID is missing."
120
  msgstr ""
121
 
122
+ #: facebook-commerce.php:2037
123
  msgid ""
124
  "A product sync is in progress. Please wait until the sync finishes before "
125
  "starting a new one."
126
  msgstr ""
127
 
128
+ #: facebook-commerce.php:2049 facebook-commerce.php:2201
129
  msgid ""
130
  "We've detected that your Facebook Product Catalog is no longer valid. This "
131
  "may happen if it was deleted, but could also be a temporary error. If the "
133
  "and setup the plugin again."
134
  msgstr ""
135
 
136
+ #: facebook-commerce.php:2225
137
  msgid "We couldn't create the feed or upload the product information."
138
  msgstr ""
139
 
140
+ #: facebook-commerce.php:2692
141
  msgid "Hi! We're here to answer any questions you may have."
142
  msgstr ""
143
 
144
+ #: facebook-commerce.php:3036
145
  msgid "Facebook for WooCommerce error:"
146
  msgstr ""
147
 
148
+ #: facebook-commerce.php:3118
149
  msgid ""
150
  "There was an error trying to retrieve information about the Facebook page: "
151
  "%s"
152
  msgstr ""
153
 
154
+ #: facebook-commerce.php:3169
155
  msgid "Get started with Messenger Customer Chat"
156
  msgstr ""
157
 
158
+ #: facebook-commerce.php:3170
159
  msgid "Get started with Instagram Shopping"
160
  msgstr ""
161
 
162
+ #: facebook-commerce.php:3405
163
  #. translators: Placeholders %1$s - original error message from Facebook API
164
  msgid "There was an issue connecting to the Facebook API: %s"
165
  msgstr ""
608
  msgid "Uninstall unsuccessful. Please try again."
609
  msgstr ""
610
 
611
+ #: includes/Products/Sync/Background.php:65
612
  msgid "Job data key \"%s\" not set"
613
  msgstr ""
614
 
615
+ #: includes/Products/Sync/Background.php:69
616
  msgid "Job data key \"%s\" is not an array"
617
  msgstr ""
618
 
619
+ #: includes/Products/Sync/Background.php:153
620
  msgid ""
621
  "There was an error trying sync products using the Catalog Batch API for job "
622
  "%s: %s"
638
  msgid "Dismiss"
639
  msgstr ""
640
 
641
+ #: includes/fbproductfeed.php:484
642
  msgid "Could not create product catalog feed directory"
643
  msgstr ""
644
 
645
+ #: includes/fbproductfeed.php:550
646
  msgid "Could not open the product catalog temporary feed file for writing"
647
  msgstr ""
648
 
649
+ #: includes/fbproductfeed.php:557
650
  msgid "Could not open the product catalog feed file for writing"
651
  msgstr ""
652
 
653
+ #: includes/fbproductfeed.php:601
654
  msgid "Could not rename the product catalog feed file"
655
  msgstr ""
656
 
includes/Handlers/Connection.php CHANGED
@@ -449,16 +449,32 @@ class Connection {
449
 
450
  if ( ! is_string( $this->external_business_id ) ) {
451
 
452
- $value = get_option( self::OPTION_EXTERNAL_BUSINESS_ID );
453
-
454
- if ( ! is_string( $value ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
455
 
456
- $value = uniqid( sanitize_title( $this->get_business_name() ) . '-', false );
457
 
458
- update_option( self::OPTION_EXTERNAL_BUSINESS_ID, $value );
459
  }
460
 
461
- $this->external_business_id = $value;
462
  }
463
 
464
  /**
@@ -653,7 +669,9 @@ class Connection {
653
 
654
  $parameters['business_config']['messenger_chat'] = [
655
  'enabled' => true,
656
- 'domains' => home_url( '/' ),
 
 
657
  ];
658
  }
659
 
449
 
450
  if ( ! is_string( $this->external_business_id ) ) {
451
 
452
+ $external_id = get_option( self::OPTION_EXTERNAL_BUSINESS_ID );
453
+
454
+ if ( ! is_string( $external_id ) ) {
455
+
456
+ /**
457
+ * Filters the shop's business external ID.
458
+ *
459
+ * This is passed to Facebook when connecting.
460
+ * Should be non-empty and without special characters, otherwise the ID will be obtained from the site URL as fallback.
461
+ *
462
+ * @since 2.0.0
463
+ *
464
+ * @param string $external_id the shop's business external ID
465
+ */
466
+ $external_id = sanitize_key( (string) apply_filters( 'wc_facebook_connection_business_id', get_bloginfo( 'name' ) ) );
467
+
468
+ if ( empty( $external_id ) ) {
469
+ $external_id = sanitize_key( str_replace( [ 'http', 'https', 'www' ], '', get_bloginfo( 'url' ) ) );
470
+ }
471
 
472
+ $external_id = uniqid( sprintf( '%s-', $external_id ), false );
473
 
474
+ update_option( self::OPTION_EXTERNAL_BUSINESS_ID, $external_id );
475
  }
476
 
477
+ $this->external_business_id = $external_id;
478
  }
479
 
480
  /**
669
 
670
  $parameters['business_config']['messenger_chat'] = [
671
  'enabled' => true,
672
+ 'domains' => [
673
+ home_url( '/' ),
674
+ ],
675
  ];
676
  }
677
 
includes/Integrations/Bookings.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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\Integrations;
12
+
13
+ defined( 'ABSPATH' ) or exit;
14
+
15
+ /**
16
+ * Integration with WooCommerce Bookings.
17
+ *
18
+ * @since 2.0.0-dev.1
19
+ */
20
+ class Bookings {
21
+
22
+
23
+ /**
24
+ * Integration constructor.
25
+ *
26
+ * @since 2.0.0-dev.3
27
+ */
28
+ public function __construct() {
29
+
30
+ add_action( 'init', [ $this, 'add_hooks' ] );
31
+ }
32
+
33
+
34
+ /**
35
+ * Adds integration hooks.
36
+ *
37
+ * @since 2.0.0-dev.3
38
+ */
39
+ public function add_hooks() {
40
+
41
+ if ( facebook_for_woocommerce()->is_plugin_active( 'woocommerce-bookings.php') ) {
42
+ add_filter( 'wc_facebook_product_price', [ $this, 'get_product_price' ], 10, 3 );
43
+ }
44
+ }
45
+
46
+
47
+ /**
48
+ * Filters the product price user for Facebook sync for Bookable products.
49
+ *
50
+ * @internal
51
+ *
52
+ * @since 2.0.0-dev.3
53
+ *
54
+ * @param int $price product price in cents
55
+ * @param float $facebook_price user defined facebook price
56
+ * @param \WC_Product $product product object
57
+ * @return int
58
+ */
59
+ public function get_product_price( $price, $facebook_price, $product ) {
60
+
61
+ if ( ! $facebook_price && $product instanceof \WC_Product && $this->is_bookable_product( $product ) ) {
62
+
63
+ $product = new \WC_Product_Booking( $product );
64
+ $display_cost = is_callable( [ $product, 'get_display_cost' ] ) ? $product->get_display_cost() : 0;
65
+
66
+ $price = (int) round( wc_get_price_to_display( $product, [ 'price' => $display_cost ] ) * 100 );
67
+ }
68
+
69
+ return $price;
70
+ }
71
+
72
+
73
+ /**
74
+ * Determines whether the current product is a WooCommerce Bookings product.
75
+ *
76
+ * @since 2.0.0-dev.3
77
+ *
78
+ * @param \WC_Product $product product object
79
+ * @return bool
80
+ */
81
+ private function is_bookable_product( \WC_Product $product ) {
82
+
83
+ return class_exists( 'WC_Product_Booking' ) && is_callable( 'is_wc_booking_product' ) && is_wc_booking_product( $product );
84
+ }
85
+
86
+
87
+ }
88
+
includes/Integrations/Integrations.php CHANGED
@@ -53,6 +53,7 @@ class Integrations {
53
 
54
  $registered_integrations = [
55
  'WC_Facebook_WPML_Injector' => '/includes/fbwpml.php',
 
56
  ];
57
 
58
  foreach ( $registered_integrations as $class_name => $path ) {
53
 
54
  $registered_integrations = [
55
  'WC_Facebook_WPML_Injector' => '/includes/fbwpml.php',
56
+ Bookings::class => '/includes/Integrations/Bookings.php',
57
  ];
58
 
59
  foreach ( $registered_integrations as $class_name => $path ) {
includes/Products.php CHANGED
@@ -10,6 +10,8 @@
10
 
11
  namespace SkyVerge\WooCommerce\Facebook;
12
 
 
 
13
  defined( 'ABSPATH' ) or exit;
14
 
15
  /**
@@ -162,21 +164,58 @@ class Products {
162
  /**
163
  * Determines whether the given product should be synced.
164
  *
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  * If a product is enabled for sync, but belongs to an excluded term, it will return as excluded from sync:
166
  * @see Products::is_sync_enabled_for_product()
167
  * @see Products::is_sync_excluded_for_product_terms()
168
  *
169
- * @since 1.10.0
170
  *
171
  * @param \WC_Product $product
172
  * @return bool
173
  */
174
- public static function product_should_be_synced( \WC_Product $product ) {
 
 
175
 
176
  // define the product to check terms on
177
- $terms_product = $product->is_type( 'variation' ) ? wc_get_product( $product->get_parent_id() ) : $product;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
 
179
- return self::is_sync_enabled_for_product( $product ) && $terms_product && ! self::is_sync_excluded_for_product_terms( $terms_product );
 
 
 
 
 
180
  }
181
 
182
 
@@ -338,4 +377,56 @@ class Products {
338
  }
339
 
340
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
  }
10
 
11
  namespace SkyVerge\WooCommerce\Facebook;
12
 
13
+ use WC_Facebook_Product;
14
+
15
  defined( 'ABSPATH' ) or exit;
16
 
17
  /**
164
  /**
165
  * Determines whether the given product should be synced.
166
  *
167
+ * @see Products::published_product_should_be_synced()
168
+ *
169
+ * @since 1.10.0
170
+ *
171
+ * @param \WC_Product $product
172
+ * @return bool
173
+ */
174
+ public static function product_should_be_synced( \WC_Product $product ) {
175
+
176
+ return 'publish' === $product->get_status() && self::published_product_should_be_synced( $product );
177
+ }
178
+
179
+
180
+ /**
181
+ * Determines whether the given product should be synced assuming the product is published.
182
+ *
183
  * If a product is enabled for sync, but belongs to an excluded term, it will return as excluded from sync:
184
  * @see Products::is_sync_enabled_for_product()
185
  * @see Products::is_sync_excluded_for_product_terms()
186
  *
187
+ * @since 2.0.0-dev.1
188
  *
189
  * @param \WC_Product $product
190
  * @return bool
191
  */
192
+ public static function published_product_should_be_synced( \WC_Product $product ) {
193
+
194
+ $should_sync = self::is_sync_enabled_for_product( $product );
195
 
196
  // define the product to check terms on
197
+ if ( $should_sync ) {
198
+ $terms_product = $product->is_type( 'variation' ) ? wc_get_product( $product->get_parent_id() ) : $product;
199
+ } else {
200
+ $terms_product = null;
201
+ }
202
+
203
+ // allow simple or variable products (and their variations) with zero or empty price - exclude other product types with zero or empty price
204
+ if ( $should_sync && ( ! $terms_product || ( ! self::get_product_price( $product ) && ! in_array( $terms_product->get_type(), [ 'simple', 'variable' ] ) ) ) ) {
205
+ $should_sync = false;
206
+ }
207
+
208
+ // exclude products that are excluded from the store catalog or from search results
209
+ if ( $should_sync && ( ! $terms_product || has_term( [ 'exclude-from-catalog', 'exclude-from-search' ], 'product_visibility', $terms_product->get_id() ) ) ) {
210
+ $should_sync = false;
211
+ }
212
 
213
+ // exclude products that belong to one of the excluded terms
214
+ if ( $should_sync && ( ! $terms_product || self::is_sync_excluded_for_product_terms( $terms_product ) ) ) {
215
+ $should_sync = false;
216
+ }
217
+
218
+ return $should_sync;
219
  }
220
 
221
 
377
  }
378
 
379
 
380
+ /**
381
+ * Gets the product price used for Facebook sync.
382
+ *
383
+ * TODO: Consider adding memoization, but ensure we can protect the implementation against price changes during the same request {WV-2020-08-20}
384
+ * See https://github.com/facebookincubator/facebook-for-woocommerce/pull/1468
385
+ *
386
+ * @since 2.0.0-dev.1
387
+ *
388
+ * @param int $price product price in cents
389
+ * @param \WC_Product $product product object
390
+ * @return int
391
+ */
392
+ public static function get_product_price( \WC_Product $product ) {
393
+
394
+ $facebook_price = $product->get_meta( WC_Facebook_Product::FB_PRODUCT_PRICE );
395
+
396
+ // use the user defined Facebook price if set
397
+ if ( is_numeric( $facebook_price ) ) {
398
+
399
+ $price = $facebook_price;
400
+
401
+ } elseif ( class_exists( 'WC_Product_Composite' ) && $product instanceof \WC_Product_Composite ) {
402
+
403
+ $price = get_option( 'woocommerce_tax_display_shop' ) === 'incl' ? $product->get_composite_price_including_tax() : $product->get_composite_price();
404
+
405
+ } elseif ( class_exists( 'WC_Product_Bundle' )
406
+ && empty( $product->get_regular_price() )
407
+ && 'bundle' === $product->get_type() ) {
408
+
409
+ // if product is a product bundle with individually priced items, we rely on their pricing
410
+ $price = wc_get_price_to_display( $product, [ 'price' => $product->get_bundle_price() ] );
411
+
412
+ } else {
413
+
414
+ $price = wc_get_price_to_display( $product, [ 'price' => $product->get_regular_price() ] );
415
+ }
416
+
417
+ $price = (int) ( $price ? round( $price * 100 ) : 0 );
418
+
419
+ /**
420
+ * Filters the product price used for Facebook sync.
421
+ *
422
+ * @since 2.0.0-dev.1
423
+ *
424
+ * @param int $price product price in cents
425
+ * @param float $facebook_price user defined facebook price
426
+ * @param \WC_Product $product product object
427
+ */
428
+ return (int) apply_filters( 'wc_facebook_product_price', $price, (float) $facebook_price, $product );
429
+ }
430
+
431
+
432
  }
includes/Products/Sync.php CHANGED
@@ -103,26 +103,8 @@ class Sync {
103
  // remove parent products because those can't be represented as Product Items
104
  $product_ids = array_diff( $product_ids, $parent_product_ids );
105
 
106
- // make sure the product should be synced and add it to the sync queue
107
- foreach ( $product_ids as $product_id ) {
108
-
109
- $woo_product = new \WC_Facebook_Product( $product_id );
110
-
111
- if ( $woo_product->is_hidden() ) {
112
- continue;
113
- }
114
-
115
- if ( get_option( 'woocommerce_hide_out_of_stock_items' ) === 'yes' && ! $woo_product->is_in_stock() ) {
116
- continue;
117
- }
118
-
119
- // skip if not enabled for sync
120
- if ( $woo_product->woo_product instanceof \WC_Product && ! Products::product_should_be_synced( $woo_product->woo_product ) ) {
121
- continue;
122
- }
123
-
124
- $this->create_or_update_products( [ $product_id ] );
125
- }
126
  }
127
 
128
 
103
  // remove parent products because those can't be represented as Product Items
104
  $product_ids = array_diff( $product_ids, $parent_product_ids );
105
 
106
+ // queue up these IDs for sync. they will only be included in the final requests if they should be synced
107
+ $this->create_or_update_products( $product_ids );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  }
109
 
110
 
includes/Products/Sync/Background.php CHANGED
@@ -12,6 +12,7 @@ namespace SkyVerge\WooCommerce\Facebook\Products\Sync;
12
 
13
  defined( 'ABSPATH' ) or exit;
14
 
 
15
  use SkyVerge\WooCommerce\Facebook\Products\Sync;
16
  use SkyVerge\WooCommerce\PluginFramework\v5_5_4 as Framework;
17
 
@@ -115,7 +116,9 @@ class Background extends Framework\SV_WP_Background_Job_Handler {
115
 
116
  try {
117
 
118
- $requests[] = $this->process_item( [ $item_id, $method ], $job );
 
 
119
 
120
  } catch ( Framework\SV_WC_Plugin_Exception $e ) {
121
 
@@ -162,7 +165,7 @@ class Background extends Framework\SV_WP_Background_Job_Handler {
162
  *
163
  * @param mixed $item
164
  * @param object|\stdClass $job
165
- * @return array
166
  * @throws Framework\SV_WC_Plugin_Exception
167
  */
168
  public function process_item( $item, $job ) {
@@ -189,7 +192,7 @@ class Background extends Framework\SV_WP_Background_Job_Handler {
189
  * @since 2.0.0
190
  *
191
  * @param string $prefixed_product_id prefixed product ID
192
- * @return array
193
  * @throws Framework\SV_WC_Plugin_Exception
194
  */
195
  private function process_item_update( $prefixed_product_id ) {
@@ -201,33 +204,40 @@ class Background extends Framework\SV_WP_Background_Job_Handler {
201
  throw new Framework\SV_WC_Plugin_Exception( "No product found with ID equal to {$product_id}." );
202
  }
203
 
204
- if ( $product->is_type( 'variation' ) ) {
205
- $product_data = $this->prepare_product_variation_data( $product );
206
- } else {
207
- $product_data = $this->prepare_product_data( $product );
208
- }
209
 
210
- // extract the retailer_id
211
- $retailer_id = $product_data['retailer_id'];
212
 
213
- // retailer_id cannot be included in the data object
214
- unset( $product_data['retailer_id'] );
 
 
 
215
 
216
- $request = [
217
- 'retailer_id' => $retailer_id,
218
- 'method' => Sync::ACTION_UPDATE,
219
- 'data' => $product_data,
220
- ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
 
222
- /**
223
- * Filters the data that will be included in a UPDATE sync request.
224
- *
225
- * @since 2.0.0
226
- *
227
- * @param array $request request data
228
- * @param \WC_Product $product product object
229
- */
230
- return apply_filters( 'wc_facebook_sync_background_item_update_request', $request, $product );
231
  }
232
 
233
 
12
 
13
  defined( 'ABSPATH' ) or exit;
14
 
15
+ use SkyVerge\WooCommerce\Facebook\Products;
16
  use SkyVerge\WooCommerce\Facebook\Products\Sync;
17
  use SkyVerge\WooCommerce\PluginFramework\v5_5_4 as Framework;
18
 
116
 
117
  try {
118
 
119
+ if ( $request = $this->process_item( [ $item_id, $method ], $job ) ) {
120
+ $requests[] = $request;
121
+ }
122
 
123
  } catch ( Framework\SV_WC_Plugin_Exception $e ) {
124
 
165
  *
166
  * @param mixed $item
167
  * @param object|\stdClass $job
168
+ * @return array|null
169
  * @throws Framework\SV_WC_Plugin_Exception
170
  */
171
  public function process_item( $item, $job ) {
192
  * @since 2.0.0
193
  *
194
  * @param string $prefixed_product_id prefixed product ID
195
+ * @return array|null
196
  * @throws Framework\SV_WC_Plugin_Exception
197
  */
198
  private function process_item_update( $prefixed_product_id ) {
204
  throw new Framework\SV_WC_Plugin_Exception( "No product found with ID equal to {$product_id}." );
205
  }
206
 
207
+ $request = null;
 
 
 
 
208
 
209
+ if ( ! Products::product_should_be_deleted( $product ) && Products::product_should_be_synced( $product ) ) {
 
210
 
211
+ if ( $product->is_type( 'variation' ) ) {
212
+ $product_data = $this->prepare_product_variation_data( $product );
213
+ } else {
214
+ $product_data = $this->prepare_product_data( $product );
215
+ }
216
 
217
+ // extract the retailer_id
218
+ $retailer_id = $product_data['retailer_id'];
219
+
220
+ // retailer_id cannot be included in the data object
221
+ unset( $product_data['retailer_id'] );
222
+
223
+ $request = [
224
+ 'retailer_id' => $retailer_id,
225
+ 'method' => Sync::ACTION_UPDATE,
226
+ 'data' => $product_data,
227
+ ];
228
+
229
+ /**
230
+ * Filters the data that will be included in a UPDATE sync request.
231
+ *
232
+ * @since 2.0.0
233
+ *
234
+ * @param array $request request data
235
+ * @param \WC_Product $product product object
236
+ */
237
+ $request = apply_filters( 'wc_facebook_sync_background_item_update_request', $request, $product );
238
+ }
239
 
240
+ return $request;
 
 
 
 
 
 
 
 
241
  }
242
 
243
 
includes/fbproduct.php CHANGED
@@ -124,46 +124,8 @@ if ( ! class_exists( 'WC_Facebook_Product' ) ) :
124
  }
125
 
126
  public function get_fb_price() {
127
- // Cache the price in this object in case of multiple calls.
128
- if ( $this->fb_price ) {
129
- return $this->fb_price;
130
- }
131
-
132
- $price = get_post_meta(
133
- $this->id,
134
- self::FB_PRODUCT_PRICE,
135
- true
136
- );
137
 
138
- if ( is_numeric( $price ) ) {
139
- return intval( round( $price * 100 ) );
140
- }
141
-
142
- // If product is composite product, we rely on their pricing.
143
- if ( class_exists( 'WC_Product_Composite' )
144
- && $this->woo_product->get_type() === 'composite' ) {
145
- $price = get_option( 'woocommerce_tax_display_shop' ) === 'incl'
146
- ? $this->woo_product->get_composite_price_including_tax()
147
- : $this->woo_product->get_composite_price();
148
- $this->fb_price = intval( round( $price * 100 ) );
149
- return $this->fb_price;
150
- }
151
-
152
- // Get regular price: regular price doesn't include sales
153
- $regular_price = floatval( $this->get_regular_price() );
154
-
155
- // If it's a bookable product, the normal price is null/0.
156
- if ( ! $regular_price && $this->is_bookable_product() ) {
157
-
158
- $product = new WC_Product_Booking( $this->woo_product );
159
- $regular_price = is_callable( [ $product, 'get_display_cost' ] ) ? $product->get_display_cost() : 0;
160
- }
161
-
162
- // Get regular price plus tax, if it's set to display and taxable
163
- // whether price includes tax is based on 'woocommerce_tax_display_shop'
164
- $price = $this->get_price_plus_tax( $regular_price );
165
- $this->fb_price = intval( round( $price * 100 ) );
166
- return $this->fb_price;
167
  }
168
 
169
 
@@ -230,6 +192,24 @@ if ( ! class_exists( 'WC_Facebook_Product' ) ) :
230
  return $image_urls;
231
  }
232
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  // Returns the parent image id for variable products only.
234
  public function get_parent_image_id() {
235
  if ( WC_Facebookcommerce_Utils::is_variation_type( $this->woo_product->get_type() ) ) {
@@ -385,29 +365,16 @@ if ( ! class_exists( 'WC_Facebook_Product' ) ) :
385
  /**
386
  * Determines whether a product should be excluded from all-products sync or the feed file.
387
  *
388
- * The plugin also avoids trying to get the Facebook ID of products where is_hidden() returns true.
389
- *
390
  * @see SkyVerge\WooCommerce\Facebook\Products\Sync::create_or_update_all_products()
391
  * @see WC_Facebook_Product_Feed::write_product_feed_file()
392
- * @see WC_Facebookcommerce_Integration::get_product_fbid()
 
393
  */
394
  public function is_hidden() {
395
- $wpid = $this->id;
396
- if ( WC_Facebookcommerce_Utils::is_variation_type( $this->get_type() ) ) {
397
- $wpid = $this->get_parent_id();
398
- }
399
- $hidden_from_catalog = has_term(
400
- 'exclude-from-catalog',
401
- 'product_visibility',
402
- $wpid
403
- );
404
- $hidden_from_search = has_term(
405
- 'exclude-from-search',
406
- 'product_visibility',
407
- $wpid
408
- );
409
 
410
- return ( $hidden_from_catalog && $hidden_from_search ) || ! $this->get_fb_price();
 
 
411
  }
412
 
413
 
@@ -574,18 +541,15 @@ if ( ! class_exists( 'WC_Facebook_Product' ) ) :
574
  ),
575
  'description' => $this->get_fb_description(),
576
  'image_url' => $image_urls[0], // The array can't be empty.
577
- 'additional_image_urls' => array_slice( $image_urls, 1 ),
578
  'url' => $product_url,
579
  'category' => $categories['categories'],
580
  'brand' => Framework\SV_WC_Helper::str_truncate( $brand, 100 ),
581
  'retailer_id' => $retailer_id,
582
  'price' => $this->get_fb_price(),
583
  'currency' => get_woocommerce_currency(),
584
- 'availability' => $this->is_in_stock() ? 'in stock' :
585
- 'out of stock',
586
- 'visibility' => ! $this->is_hidden()
587
- ? \WC_Facebookcommerce_Integration::FB_SHOP_PRODUCT_VISIBLE
588
- : \WC_Facebookcommerce_Integration::FB_SHOP_PRODUCT_HIDDEN,
589
  );
590
 
591
  // Only use checkout URLs if they exist.
124
  }
125
 
126
  public function get_fb_price() {
 
 
 
 
 
 
 
 
 
 
127
 
128
+ return Products::get_product_price( $this->woo_product );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  }
130
 
131
 
192
  return $image_urls;
193
  }
194
 
195
+
196
+ /**
197
+ * Gets the list of additional image URLs for the product from the complete list of image URLs.
198
+ *
199
+ * It assumes the first URL will be used as the product image.
200
+ * It returns 20 or less image URLs because Facebook doesn't allow more items on the additional_image_urls field.
201
+ *
202
+ * @since 2.0.2
203
+ *
204
+ * @param array $image_urls all image URLs for the product
205
+ * @return array
206
+ */
207
+ private function get_additional_image_urls( $image_urls ) {
208
+
209
+ return array_slice( $image_urls, 1, 20 );
210
+ }
211
+
212
+
213
  // Returns the parent image id for variable products only.
214
  public function get_parent_image_id() {
215
  if ( WC_Facebookcommerce_Utils::is_variation_type( $this->woo_product->get_type() ) ) {
365
  /**
366
  * Determines whether a product should be excluded from all-products sync or the feed file.
367
  *
 
 
368
  * @see SkyVerge\WooCommerce\Facebook\Products\Sync::create_or_update_all_products()
369
  * @see WC_Facebook_Product_Feed::write_product_feed_file()
370
+ *
371
+ * @deprecated 2.0.2
372
  */
373
  public function is_hidden() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374
 
375
+ wc_deprecated_function( __METHOD__, '2.0.2', 'Products::product_should_be_synced()' );
376
+
377
+ return $this->woo_product instanceof \WC_Product && ! Products::product_should_be_synced( $this->woo_product );
378
  }
379
 
380
 
541
  ),
542
  'description' => $this->get_fb_description(),
543
  'image_url' => $image_urls[0], // The array can't be empty.
544
+ 'additional_image_urls' => $this->get_additional_image_urls( $image_urls ),
545
  'url' => $product_url,
546
  'category' => $categories['categories'],
547
  'brand' => Framework\SV_WC_Helper::str_truncate( $brand, 100 ),
548
  'retailer_id' => $retailer_id,
549
  'price' => $this->get_fb_price(),
550
  'currency' => get_woocommerce_currency(),
551
+ 'availability' => $this->is_in_stock() ? 'in stock' : 'out of stock',
552
+ 'visibility' => Products::is_product_visible( $this->woo_product ) ? \WC_Facebookcommerce_Integration::FB_SHOP_PRODUCT_VISIBLE : \WC_Facebookcommerce_Integration::FB_SHOP_PRODUCT_HIDDEN,
 
 
 
553
  );
554
 
555
  // Only use checkout URLs if they exist.
includes/fbproductfeed.php CHANGED
@@ -12,6 +12,7 @@ if ( ! defined( 'ABSPATH' ) ) {
12
  exit;
13
  }
14
 
 
15
  use SkyVerge\WooCommerce\Facebook\Products\Feed;
16
  use SkyVerge\WooCommerce\PluginFramework\v5_5_4 as Framework;
17
 
@@ -565,16 +566,13 @@ if ( ! class_exists( 'WC_Facebook_Product_Feed' ) ) :
565
 
566
  $woo_product = new WC_Facebook_Product( $wp_id );
567
 
568
- if ( $woo_product->is_hidden() ) {
569
- continue;
570
- }
571
-
572
- if ( get_option( 'woocommerce_hide_out_of_stock_items' ) === 'yes' && ! $woo_product->is_in_stock() ) {
573
  continue;
574
  }
575
 
576
  // skip if not enabled for sync
577
- if ( $woo_product->woo_product instanceof \WC_Product && ! SkyVerge\WooCommerce\Facebook\Products::product_should_be_synced( $woo_product->woo_product ) ) {
578
  continue;
579
  }
580
 
@@ -737,6 +735,11 @@ if ( ! class_exists( 'WC_Facebook_Product_Feed' ) ) :
737
  $product_data['default_product'] = '';
738
  }
739
 
 
 
 
 
 
740
  return $product_data['retailer_id'] . ',' .
741
  static::format_string_for_feed( $product_data['name'] ) . ',' .
742
  static::format_string_for_feed( $product_data['description'] ) . ',' .
12
  exit;
13
  }
14
 
15
+ use SkyVerge\WooCommerce\Facebook\Products;
16
  use SkyVerge\WooCommerce\Facebook\Products\Feed;
17
  use SkyVerge\WooCommerce\PluginFramework\v5_5_4 as Framework;
18
 
566
 
567
  $woo_product = new WC_Facebook_Product( $wp_id );
568
 
569
+ // skip if we don't have a valid product object
570
+ if ( ! $woo_product->woo_product instanceof \WC_Product ) {
 
 
 
571
  continue;
572
  }
573
 
574
  // skip if not enabled for sync
575
+ if ( ! Products::product_should_be_synced( $woo_product->woo_product ) ) {
576
  continue;
577
  }
578
 
735
  $product_data['default_product'] = '';
736
  }
737
 
738
+ // when dealing with the feed file, only set out-of-stock products as hidden
739
+ if ( Products::product_should_be_deleted( $woo_product->woo_product ) ) {
740
+ $product_data['visibility'] = \WC_Facebookcommerce_Integration::FB_SHOP_PRODUCT_HIDDEN;
741
+ }
742
+
743
  return $product_data['retailer_id'] . ',' .
744
  static::format_string_for_feed( $product_data['name'] ) . ',' .
745
  static::format_string_for_feed( $product_data['description'] ) . ',' .
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: facebook, automattic, woothemes
3
  Tags: facebook, shop, catalog, advertise, pixel, product
4
  Requires at least: 4.4
5
  Tested up to: 5.3.2
6
- Stable tag: 2.0.1
7
  Requires PHP: 5.6 or greater
8
  MySQL: 5.6 or greater
9
  License: GPLv2 or later
@@ -39,6 +39,13 @@ When opening a bug on GitHub, please give us as many details as possible.
39
 
40
  == Changelog ==
41
 
 
 
 
 
 
 
 
42
  = 2020.08.17 - version 2.0.1 =
43
  * Fix - Ensure the configured business name is never empty when connecting to Facebook
44
 
3
  Tags: facebook, shop, catalog, advertise, pixel, product
4
  Requires at least: 4.4
5
  Tested up to: 5.3.2
6
+ Stable tag: 2.0.2
7
  Requires PHP: 5.6 or greater
8
  MySQL: 5.6 or greater
9
  License: GPLv2 or later
39
 
40
  == Changelog ==
41
 
42
+ = 2020.09.25 - version 2.0.2 =
43
+ * Tweak - Allow simple and variable products with zero/empty price to sync to Facebook
44
+ * Tweak - Use the bundle price for Product Bundles products with individually priced items
45
+ * Fix - Update connection parameters to use an array to pass the Messenger domain
46
+ * Fix - Ensure out-of-stock products are marked as such in Facebook when the feed file replacement is run
47
+ * Fix - Address a potential error when connecting from a site whose title contains special characters
48
+
49
  = 2020.08.17 - version 2.0.1 =
50
  * Fix - Ensure the configured business name is never empty when connecting to Facebook
51