Facebook for WooCommerce - Version 3.0.6

Version Description

  • 2022-12-13 =
  • Dev - Add node and npm version restrictions.
  • Fix - PHP Warning: Attempt to read property on array in Tracker.php.
  • Fix - Deprecated notice fix.
  • Fix - Facebook Sync status is incorrect when a product has catalog visibility hidden.
  • Fix - Issue in running Background Process Test debug tool.
  • Tweak - WC 7.2 compatibility.
Download this release

Release Info

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

Code changes from version 3.0.5 to 3.0.6

changelog.txt CHANGED
@@ -1,5 +1,13 @@
1
  *** Facebook for WooCommerce Changelog ***
2
 
 
 
 
 
 
 
 
 
3
  = 3.0.5 - 2022-11-30 =
4
  * Add - Debug tools to help reset settings, delete background options and delete catalog products.
5
  * Add - Inbox note about Facebook menu moved under the Marketing menu.
1
  *** Facebook for WooCommerce Changelog ***
2
 
3
+ = 3.0.6 - 2022-12-13 =
4
+ * Dev - Add node and npm version restrictions.
5
+ * Fix - PHP Warning: Attempt to read property on array in Tracker.php.
6
+ * Fix - Deprecated notice fix.
7
+ * Fix - Facebook Sync status is incorrect when a product has catalog visibility hidden.
8
+ * Fix - Issue in running Background Process Test debug tool.
9
+ * Tweak - WC 7.2 compatibility.
10
+
11
  = 3.0.5 - 2022-11-30 =
12
  * Add - Debug tools to help reset settings, delete background options and delete catalog products.
13
  * Add - Inbox note about Facebook menu moved under the Marketing menu.
facebook-commerce.php CHANGED
@@ -769,6 +769,14 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
769
  $sync_mode = isset( $_POST['wc_facebook_sync_mode'] )
770
  ? sanitize_text_field( wp_unslash( $_POST['wc_facebook_sync_mode'] ) )
771
  : Admin::SYNC_MODE_SYNC_DISABLED;
 
 
 
 
 
 
 
 
772
  // phpcs:enable WordPress.Security.NonceVerification.Missing
773
  $sync_enabled = Admin::SYNC_MODE_SYNC_DISABLED !== $sync_mode;
774
 
@@ -776,6 +784,7 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
776
  // force to Sync and hide
777
  $sync_mode = Admin::SYNC_MODE_SYNC_AND_HIDE;
778
  }
 
779
  $products_to_delete_from_facebook = $this->get_removed_from_sync_products_to_delete();
780
  if ( $product->is_type( 'variable' ) ) {
781
  // check variations for deletion
769
  $sync_mode = isset( $_POST['wc_facebook_sync_mode'] )
770
  ? sanitize_text_field( wp_unslash( $_POST['wc_facebook_sync_mode'] ) )
771
  : Admin::SYNC_MODE_SYNC_DISABLED;
772
+
773
+ // Restore sync mode if product is marked as visible and meet all the other criteria for sync.
774
+ $catalog_visibility = isset( $_POST['_visibility'] ) ? wc_clean( wp_unslash( $_POST['_visibility'] ) ) : null;
775
+ if ( $catalog_visibility && 'hidden' !== $catalog_visibility && $product->is_visible() && $sync_mode !== Admin::SYNC_MODE_SYNC_AND_HIDE ) {
776
+ $sync_mode = facebook_for_woocommerce()->get_product_sync_validator( $product )->passes_all_checks_except_sync_field()
777
+ ? Admin::SYNC_MODE_SYNC_AND_SHOW : $sync_mode;
778
+ }
779
+
780
  // phpcs:enable WordPress.Security.NonceVerification.Missing
781
  $sync_enabled = Admin::SYNC_MODE_SYNC_DISABLED !== $sync_mode;
782
 
784
  // force to Sync and hide
785
  $sync_mode = Admin::SYNC_MODE_SYNC_AND_HIDE;
786
  }
787
+
788
  $products_to_delete_from_facebook = $this->get_removed_from_sync_products_to_delete();
789
  if ( $product->is_type( 'variable' ) ) {
790
  // check variations for deletion
facebook-for-woocommerce.php CHANGED
@@ -11,11 +11,12 @@
11
  * 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.
12
  * Author: Facebook
13
  * Author URI: https://www.facebook.com/
14
- * Version: 3.0.5
 
15
  * Text Domain: facebook-for-woocommerce
16
  * Tested up to: 6.1
17
- * WC requires at least: 5.3
18
- * WC tested up to: 5.4
19
  * Requires PHP: 7.2
20
  *
21
  * @package FacebookCommerce
@@ -44,7 +45,7 @@ class WC_Facebook_Loader {
44
  /**
45
  * @var string the plugin version. This must be in the main plugin file to be automatically bumped by Woorelease.
46
  */
47
- const PLUGIN_VERSION = '3.0.5'; // WRCS: DEFINED_VERSION.
48
 
49
  // Minimum PHP version required by this plugin.
50
  const MINIMUM_PHP_VERSION = '7.2.0';
11
  * 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.
12
  * Author: Facebook
13
  * Author URI: https://www.facebook.com/
14
+ * Version: 3.0.6
15
+ * Requires at least: 5.6
16
  * Text Domain: facebook-for-woocommerce
17
  * Tested up to: 6.1
18
+ * WC requires at least: 5.4
19
+ * WC tested up to: 7.2
20
  * Requires PHP: 7.2
21
  *
22
  * @package FacebookCommerce
45
  /**
46
  * @var string the plugin version. This must be in the main plugin file to be automatically bumped by Woorelease.
47
  */
48
+ const PLUGIN_VERSION = '3.0.6'; // WRCS: DEFINED_VERSION.
49
 
50
  // Minimum PHP version required by this plugin.
51
  const MINIMUM_PHP_VERSION = '7.2.0';
i18n/languages/facebook-for-woocommerce.pot CHANGED
@@ -2,14 +2,14 @@
2
  # This file is distributed under the same license as the Facebook for WooCommerce plugin.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: Facebook for WooCommerce 3.0.5\n"
6
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/facebook-for-woocommerce\n"
7
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
8
  "Language-Team: LANGUAGE <LL@li.org>\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=UTF-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
- "POT-Creation-Date: 2022-11-30T15:17:13+00:00\n"
13
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
14
  "X-Generator: WP-CLI 2.7.1\n"
15
  "X-Domain: facebook-for-woocommerce\n"
@@ -17,7 +17,7 @@ msgstr ""
17
  #. Plugin Name of the plugin
18
  #: class-wc-facebookcommerce.php:733
19
  #: facebook-commerce.php:198
20
- #: includes/Admin.php:1467
21
  #: includes/Admin/Settings.php:93
22
  #: includes/Admin/Settings.php:160
23
  msgid "Facebook for WooCommerce"
@@ -91,69 +91,69 @@ msgid "Facebook Commerce and Dynamic Ads (Pixel) Extension"
91
  msgstr ""
92
 
93
  #. translators: %1$s is referring to facebook product group id.
94
- #: facebook-commerce.php:1251
95
  msgid "Nothing to update for product group for %1$s"
96
  msgstr ""
97
 
98
- #: facebook-commerce.php:1936
99
  msgid "Your connection has expired."
100
  msgstr ""
101
 
102
- #: facebook-commerce.php:1936
103
  msgid "Please click Manage connection > Advanced Options > Update Token to refresh your connection to Facebook."
104
  msgstr ""
105
 
106
  #. translators: Placeholders %s - error message
107
- #: facebook-commerce.php:1943
108
  msgid "There was an error trying to sync the products to Facebook. %s"
109
  msgstr ""
110
 
111
- #: facebook-commerce.php:1962
112
  msgid "Product sync is disabled."
113
  msgstr ""
114
 
115
- #: facebook-commerce.php:1967
116
  msgid "The plugin is not configured or the Catalog ID is missing."
117
  msgstr ""
118
 
119
- #: facebook-commerce.php:1987
120
  msgid "A product sync is in progress. Please wait until the sync finishes before starting a new one."
121
  msgstr ""
122
 
123
- #: facebook-commerce.php:2003
124
  msgid "We've detected that your Facebook Product Catalog is no longer valid. This may happen if it was deleted, but could also be a temporary error. If the error persists, please click Manage connection > Advanced Options > Remove and setup the plugin again."
125
  msgstr ""
126
 
127
- #: facebook-commerce.php:2375
128
  msgid "Hi! We're here to answer any questions you may have."
129
  msgstr ""
130
 
131
- #: facebook-commerce.php:2687
132
  msgid "Facebook for WooCommerce error:"
133
  msgstr ""
134
 
135
  #. translators: Placeholders %1$s - original error message from Facebook API
136
- #: facebook-commerce.php:2922
137
  msgid "There was an issue connecting to the Facebook API: %s"
138
  msgstr ""
139
 
140
  #. translators: %1$s - plugin name, %2$s - minimum WordPress version required, %3$s - update WordPress link open, %4$s - update WordPress link close
141
- #: facebook-for-woocommerce.php:222
142
  msgid "%1$s requires WordPress version %2$s or higher. Please %3$supdate WordPress &raquo;%4$s"
143
  msgstr ""
144
 
145
  #. translators: %1$s - Plugin Name, %2$s - activate WooCommerce link open, %3$s - activate WooCommerce link close.
146
- #: facebook-for-woocommerce.php:248
147
  msgid "%1$s requires WooCommerce to be activated. Please %2$sactivate WooCommerce%3$s."
148
  msgstr ""
149
 
150
  #. translators: %1$s - Plugin Name, %2$s - install WooCommerce link open, %3$s - install WooCommerce link close.
151
- #: facebook-for-woocommerce.php:265
152
  msgid "%1$s requires WooCommerce to be installed and activated. Please %2$sinstall WooCommerce%3$s."
153
  msgstr ""
154
 
155
  #. translators: %1$s - Plugin Name, %2$s - minimum WooCommerce version, %3$s - update WooCommerce link open, %4$s - update WooCommerce link close, %5$s - download minimum WooCommerce link open, %6$s - download minimum WooCommerce link close.
156
- #: facebook-for-woocommerce.php:285
157
  msgid "%1$s requires WooCommerce version %2$s or higher. Please %3$supdate WooCommerce%4$s to the latest version, or %5$sdownload the minimum required version &raquo;%6$s"
158
  msgstr ""
159
 
@@ -205,8 +205,8 @@ msgid "You're removing a product from the Facebook sync that is currently listed
205
  msgstr ""
206
 
207
  #: includes/Admin.php:421
208
- #: includes/Admin.php:1169
209
- #: includes/Admin.php:1306
210
  msgid "Facebook sync"
211
  msgstr ""
212
 
@@ -222,8 +222,8 @@ msgstr ""
222
 
223
  #: includes/Admin.php:449
224
  #: includes/Admin.php:474
225
- #: includes/Admin.php:1173
226
- #: includes/Admin.php:1310
227
  msgid "Do not sync"
228
  msgstr ""
229
 
@@ -262,70 +262,70 @@ msgstr[1] ""
262
  msgid "%1$sHeads up!%2$s Facebook's %3$sCommerce Policies%4$s do not support selling virtual products, so we have hidden your synced Virtual products in your Facebook catalog. You may still advertise Virtual products on Facebook."
263
  msgstr ""
264
 
265
- #: includes/Admin.php:1171
266
- #: includes/Admin.php:1308
267
  msgid "Sync and show in catalog"
268
  msgstr ""
269
 
270
- #: includes/Admin.php:1172
271
- #: includes/Admin.php:1309
272
  msgid "Sync and hide in catalog"
273
  msgstr ""
274
 
275
- #: includes/Admin.php:1182
276
- #: includes/Admin.php:1322
277
  msgid "Facebook Description"
278
  msgstr ""
279
 
280
- #: includes/Admin.php:1184
281
- #: includes/Admin.php:1324
282
  msgid "Custom (plain-text only) description for product on Facebook. If blank, product description will be used. If product description is blank, shortname will be used."
283
  msgstr ""
284
 
285
- #: includes/Admin.php:1195
286
- #: includes/Admin.php:1337
287
  msgid "Facebook Product Image"
288
  msgstr ""
289
 
290
- #: includes/Admin.php:1197
291
- #: includes/Admin.php:1339
292
  msgid "Choose the product image that should be synced to the Facebook catalog for this product. If using a custom image, please enter an absolute URL (e.g. https://domain.com/image.jpg)."
293
  msgstr ""
294
 
295
- #: includes/Admin.php:1199
296
  msgid "Use WooCommerce image"
297
  msgstr ""
298
 
299
- #: includes/Admin.php:1200
300
- #: includes/Admin.php:1343
301
  msgid "Use custom image"
302
  msgstr ""
303
 
304
- #: includes/Admin.php:1211
305
- #: includes/Admin.php:1355
306
  msgid "Custom Image URL"
307
  msgstr ""
308
 
309
  #. translators: Placeholders %1$s - WC currency symbol
310
- #: includes/Admin.php:1222
311
- #: includes/Admin.php:1368
312
  msgid "Facebook Price (%1$s)"
313
  msgstr ""
314
 
315
- #: includes/Admin.php:1226
316
- #: includes/Admin.php:1372
317
  msgid "Custom price for product on Facebook. Please enter in monetary decimal (.) format without thousand separators and currency symbols. If blank, product price will be used."
318
  msgstr ""
319
 
320
- #: includes/Admin.php:1341
321
  msgid "Use variation image"
322
  msgstr ""
323
 
324
- #: includes/Admin.php:1342
325
  msgid "Use parent image"
326
  msgstr ""
327
 
328
- #: includes/Admin.php:1469
329
  msgid "Close modal panel"
330
  msgstr ""
331
 
@@ -905,35 +905,42 @@ msgid ""
905
  "\t\t\t\t\tYour hosting provider can do this for you. %4$sHere are some resources to help you upgrade%5$s and to explain PHP versions further."
906
  msgstr ""
907
 
 
908
  #. translators: Placeholders: %s - user-friendly error message
909
- #: includes/Framework/Utilities/BackgroundJobHandler.php:613
910
  #: includes/Products/Sync/Background.php:59
911
  msgid "Job data key \"%s\" not set"
912
  msgstr ""
913
 
 
914
  #. translators: Placeholders: %s - user-friendly error message
915
  #: includes/Framework/Utilities/BackgroundJobHandler.php:617
916
  #: includes/Products/Sync/Background.php:64
917
  msgid "Job data key \"%s\" is not an array"
918
  msgstr ""
919
 
920
- #: includes/Framework/Utilities/BackgroundJobHandler.php:976
 
 
 
 
 
921
  msgid "Background Processing Test"
922
  msgstr ""
923
 
924
- #: includes/Framework/Utilities/BackgroundJobHandler.php:977
925
  msgid "Run Test"
926
  msgstr ""
927
 
928
- #: includes/Framework/Utilities/BackgroundJobHandler.php:978
929
  msgid "This tool will test whether your server is capable of processing background jobs."
930
  msgstr ""
931
 
932
- #: includes/Framework/Utilities/BackgroundJobHandler.php:996
933
  msgid "Success! You should be able to process background jobs."
934
  msgstr ""
935
 
936
- #: includes/Framework/Utilities/BackgroundJobHandler.php:999
937
  msgid "Could not connect. Please ask your hosting company to ensure your server has loopback connections enabled."
938
  msgstr ""
939
 
@@ -968,59 +975,59 @@ msgstr ""
968
  msgid "There was an error trying sync products using the Catalog Batch API for job %1$s: %2$s"
969
  msgstr ""
970
 
971
- #: includes/ProductSync/ProductValidator.php:196
972
  msgid "Product sync is globally disabled."
973
  msgstr ""
974
 
975
- #: includes/ProductSync/ProductValidator.php:209
976
  msgid "Product is not published."
977
  msgstr ""
978
 
979
- #: includes/ProductSync/ProductValidator.php:220
980
  msgid "Product must be in stock."
981
  msgstr ""
982
 
983
- #: includes/ProductSync/ProductValidator.php:235
984
  msgid "This product cannot be synced to Facebook because it is hidden from your store catalog."
985
  msgstr ""
986
 
987
- #: includes/ProductSync/ProductValidator.php:250
988
  msgid "Product excluded because of categories."
989
  msgstr ""
990
 
991
- #: includes/ProductSync/ProductValidator.php:257
992
  msgid "Product excluded because of tags."
993
  msgstr ""
994
 
995
- #: includes/ProductSync/ProductValidator.php:268
996
  msgid "Sync disabled in product field."
997
  msgstr ""
998
 
999
- #: includes/ProductSync/ProductValidator.php:278
1000
  msgid "Product excluded by wc_facebook_should_sync_product filter."
1001
  msgstr ""
1002
 
1003
- #: includes/ProductSync/ProductValidator.php:314
1004
  msgid "If product is not simple, variable or variation it must have a price."
1005
  msgstr ""
1006
 
1007
- #: includes/ProductSync/ProductValidator.php:340
1008
  msgid "Product description is all capital letters. Please change the description to sentence case in order to allow synchronization of your product."
1009
  msgstr ""
1010
 
1011
- #: includes/ProductSync/ProductValidator.php:343
1012
  msgid "Product description is too long. Maximum allowed length is 5000 characters."
1013
  msgstr ""
1014
 
1015
- #: includes/ProductSync/ProductValidator.php:362
1016
  msgid "Product title is all capital letters. Please change the title to sentence case in order to allow synchronization of your product."
1017
  msgstr ""
1018
 
1019
- #: includes/ProductSync/ProductValidator.php:365
1020
  msgid "Product title is too long. Maximum allowed length is 150 characters."
1021
  msgstr ""
1022
 
1023
- #: includes/ProductSync/ProductValidator.php:389
1024
  msgid "Too many attributes selected for product. Use 4 or less."
1025
  msgstr ""
1026
 
2
  # This file is distributed under the same license as the Facebook for WooCommerce plugin.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: Facebook for WooCommerce 3.0.6\n"
6
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/facebook-for-woocommerce\n"
7
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
8
  "Language-Team: LANGUAGE <LL@li.org>\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=UTF-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
+ "POT-Creation-Date: 2022-12-13T08:15:27+00:00\n"
13
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
14
  "X-Generator: WP-CLI 2.7.1\n"
15
  "X-Domain: facebook-for-woocommerce\n"
17
  #. Plugin Name of the plugin
18
  #: class-wc-facebookcommerce.php:733
19
  #: facebook-commerce.php:198
20
+ #: includes/Admin.php:1472
21
  #: includes/Admin/Settings.php:93
22
  #: includes/Admin/Settings.php:160
23
  msgid "Facebook for WooCommerce"
91
  msgstr ""
92
 
93
  #. translators: %1$s is referring to facebook product group id.
94
+ #: facebook-commerce.php:1260
95
  msgid "Nothing to update for product group for %1$s"
96
  msgstr ""
97
 
98
+ #: facebook-commerce.php:1945
99
  msgid "Your connection has expired."
100
  msgstr ""
101
 
102
+ #: facebook-commerce.php:1945
103
  msgid "Please click Manage connection > Advanced Options > Update Token to refresh your connection to Facebook."
104
  msgstr ""
105
 
106
  #. translators: Placeholders %s - error message
107
+ #: facebook-commerce.php:1952
108
  msgid "There was an error trying to sync the products to Facebook. %s"
109
  msgstr ""
110
 
111
+ #: facebook-commerce.php:1971
112
  msgid "Product sync is disabled."
113
  msgstr ""
114
 
115
+ #: facebook-commerce.php:1976
116
  msgid "The plugin is not configured or the Catalog ID is missing."
117
  msgstr ""
118
 
119
+ #: facebook-commerce.php:1996
120
  msgid "A product sync is in progress. Please wait until the sync finishes before starting a new one."
121
  msgstr ""
122
 
123
+ #: facebook-commerce.php:2012
124
  msgid "We've detected that your Facebook Product Catalog is no longer valid. This may happen if it was deleted, but could also be a temporary error. If the error persists, please click Manage connection > Advanced Options > Remove and setup the plugin again."
125
  msgstr ""
126
 
127
+ #: facebook-commerce.php:2384
128
  msgid "Hi! We're here to answer any questions you may have."
129
  msgstr ""
130
 
131
+ #: facebook-commerce.php:2696
132
  msgid "Facebook for WooCommerce error:"
133
  msgstr ""
134
 
135
  #. translators: Placeholders %1$s - original error message from Facebook API
136
+ #: facebook-commerce.php:2931
137
  msgid "There was an issue connecting to the Facebook API: %s"
138
  msgstr ""
139
 
140
  #. translators: %1$s - plugin name, %2$s - minimum WordPress version required, %3$s - update WordPress link open, %4$s - update WordPress link close
141
+ #: facebook-for-woocommerce.php:223
142
  msgid "%1$s requires WordPress version %2$s or higher. Please %3$supdate WordPress &raquo;%4$s"
143
  msgstr ""
144
 
145
  #. translators: %1$s - Plugin Name, %2$s - activate WooCommerce link open, %3$s - activate WooCommerce link close.
146
+ #: facebook-for-woocommerce.php:249
147
  msgid "%1$s requires WooCommerce to be activated. Please %2$sactivate WooCommerce%3$s."
148
  msgstr ""
149
 
150
  #. translators: %1$s - Plugin Name, %2$s - install WooCommerce link open, %3$s - install WooCommerce link close.
151
+ #: facebook-for-woocommerce.php:266
152
  msgid "%1$s requires WooCommerce to be installed and activated. Please %2$sinstall WooCommerce%3$s."
153
  msgstr ""
154
 
155
  #. translators: %1$s - Plugin Name, %2$s - minimum WooCommerce version, %3$s - update WooCommerce link open, %4$s - update WooCommerce link close, %5$s - download minimum WooCommerce link open, %6$s - download minimum WooCommerce link close.
156
+ #: facebook-for-woocommerce.php:286
157
  msgid "%1$s requires WooCommerce version %2$s or higher. Please %3$supdate WooCommerce%4$s to the latest version, or %5$sdownload the minimum required version &raquo;%6$s"
158
  msgstr ""
159
 
205
  msgstr ""
206
 
207
  #: includes/Admin.php:421
208
+ #: includes/Admin.php:1175
209
+ #: includes/Admin.php:1311
210
  msgid "Facebook sync"
211
  msgstr ""
212
 
222
 
223
  #: includes/Admin.php:449
224
  #: includes/Admin.php:474
225
+ #: includes/Admin.php:1179
226
+ #: includes/Admin.php:1315
227
  msgid "Do not sync"
228
  msgstr ""
229
 
262
  msgid "%1$sHeads up!%2$s Facebook's %3$sCommerce Policies%4$s do not support selling virtual products, so we have hidden your synced Virtual products in your Facebook catalog. You may still advertise Virtual products on Facebook."
263
  msgstr ""
264
 
265
+ #: includes/Admin.php:1177
266
+ #: includes/Admin.php:1313
267
  msgid "Sync and show in catalog"
268
  msgstr ""
269
 
270
+ #: includes/Admin.php:1178
271
+ #: includes/Admin.php:1314
272
  msgid "Sync and hide in catalog"
273
  msgstr ""
274
 
275
+ #: includes/Admin.php:1188
276
+ #: includes/Admin.php:1327
277
  msgid "Facebook Description"
278
  msgstr ""
279
 
280
+ #: includes/Admin.php:1190
281
+ #: includes/Admin.php:1329
282
  msgid "Custom (plain-text only) description for product on Facebook. If blank, product description will be used. If product description is blank, shortname will be used."
283
  msgstr ""
284
 
285
+ #: includes/Admin.php:1201
286
+ #: includes/Admin.php:1342
287
  msgid "Facebook Product Image"
288
  msgstr ""
289
 
290
+ #: includes/Admin.php:1203
291
+ #: includes/Admin.php:1344
292
  msgid "Choose the product image that should be synced to the Facebook catalog for this product. If using a custom image, please enter an absolute URL (e.g. https://domain.com/image.jpg)."
293
  msgstr ""
294
 
295
+ #: includes/Admin.php:1205
296
  msgid "Use WooCommerce image"
297
  msgstr ""
298
 
299
+ #: includes/Admin.php:1206
300
+ #: includes/Admin.php:1348
301
  msgid "Use custom image"
302
  msgstr ""
303
 
304
+ #: includes/Admin.php:1217
305
+ #: includes/Admin.php:1360
306
  msgid "Custom Image URL"
307
  msgstr ""
308
 
309
  #. translators: Placeholders %1$s - WC currency symbol
310
+ #: includes/Admin.php:1228
311
+ #: includes/Admin.php:1373
312
  msgid "Facebook Price (%1$s)"
313
  msgstr ""
314
 
315
+ #: includes/Admin.php:1232
316
+ #: includes/Admin.php:1377
317
  msgid "Custom price for product on Facebook. Please enter in monetary decimal (.) format without thousand separators and currency symbols. If blank, product price will be used."
318
  msgstr ""
319
 
320
+ #: includes/Admin.php:1346
321
  msgid "Use variation image"
322
  msgstr ""
323
 
324
+ #: includes/Admin.php:1347
325
  msgid "Use parent image"
326
  msgstr ""
327
 
328
+ #: includes/Admin.php:1474
329
  msgid "Close modal panel"
330
  msgstr ""
331
 
905
  "\t\t\t\t\tYour hosting provider can do this for you. %4$sHere are some resources to help you upgrade%5$s and to explain PHP versions further."
906
  msgstr ""
907
 
908
+ #. translators: %s - string representing data key.
909
  #. translators: Placeholders: %s - user-friendly error message
910
+ #: includes/Framework/Utilities/BackgroundJobHandler.php:612
911
  #: includes/Products/Sync/Background.php:59
912
  msgid "Job data key \"%s\" not set"
913
  msgstr ""
914
 
915
+ #. translators: %s - string representing data key.
916
  #. translators: Placeholders: %s - user-friendly error message
917
  #: includes/Framework/Utilities/BackgroundJobHandler.php:617
918
  #: includes/Products/Sync/Background.php:64
919
  msgid "Job data key \"%s\" is not an array"
920
  msgstr ""
921
 
922
+ #. translators: %d - interval in minutes.
923
+ #: includes/Framework/Utilities/BackgroundJobHandler.php:827
924
+ msgid "Every %d Minutes"
925
+ msgstr ""
926
+
927
+ #: includes/Framework/Utilities/BackgroundJobHandler.php:975
928
  msgid "Background Processing Test"
929
  msgstr ""
930
 
931
+ #: includes/Framework/Utilities/BackgroundJobHandler.php:976
932
  msgid "Run Test"
933
  msgstr ""
934
 
935
+ #: includes/Framework/Utilities/BackgroundJobHandler.php:977
936
  msgid "This tool will test whether your server is capable of processing background jobs."
937
  msgstr ""
938
 
939
+ #: includes/Framework/Utilities/BackgroundJobHandler.php:994
940
  msgid "Success! You should be able to process background jobs."
941
  msgstr ""
942
 
943
+ #: includes/Framework/Utilities/BackgroundJobHandler.php:997
944
  msgid "Could not connect. Please ask your hosting company to ensure your server has loopback connections enabled."
945
  msgstr ""
946
 
975
  msgid "There was an error trying sync products using the Catalog Batch API for job %1$s: %2$s"
976
  msgstr ""
977
 
978
+ #: includes/ProductSync/ProductValidator.php:229
979
  msgid "Product sync is globally disabled."
980
  msgstr ""
981
 
982
+ #: includes/ProductSync/ProductValidator.php:242
983
  msgid "Product is not published."
984
  msgstr ""
985
 
986
+ #: includes/ProductSync/ProductValidator.php:253
987
  msgid "Product must be in stock."
988
  msgstr ""
989
 
990
+ #: includes/ProductSync/ProductValidator.php:268
991
  msgid "This product cannot be synced to Facebook because it is hidden from your store catalog."
992
  msgstr ""
993
 
994
+ #: includes/ProductSync/ProductValidator.php:283
995
  msgid "Product excluded because of categories."
996
  msgstr ""
997
 
998
+ #: includes/ProductSync/ProductValidator.php:290
999
  msgid "Product excluded because of tags."
1000
  msgstr ""
1001
 
1002
+ #: includes/ProductSync/ProductValidator.php:301
1003
  msgid "Sync disabled in product field."
1004
  msgstr ""
1005
 
1006
+ #: includes/ProductSync/ProductValidator.php:311
1007
  msgid "Product excluded by wc_facebook_should_sync_product filter."
1008
  msgstr ""
1009
 
1010
+ #: includes/ProductSync/ProductValidator.php:347
1011
  msgid "If product is not simple, variable or variation it must have a price."
1012
  msgstr ""
1013
 
1014
+ #: includes/ProductSync/ProductValidator.php:373
1015
  msgid "Product description is all capital letters. Please change the description to sentence case in order to allow synchronization of your product."
1016
  msgstr ""
1017
 
1018
+ #: includes/ProductSync/ProductValidator.php:376
1019
  msgid "Product description is too long. Maximum allowed length is 5000 characters."
1020
  msgstr ""
1021
 
1022
+ #: includes/ProductSync/ProductValidator.php:395
1023
  msgid "Product title is all capital letters. Please change the title to sentence case in order to allow synchronization of your product."
1024
  msgstr ""
1025
 
1026
+ #: includes/ProductSync/ProductValidator.php:398
1027
  msgid "Product title is too long. Maximum allowed length is 150 characters."
1028
  msgstr ""
1029
 
1030
+ #: includes/ProductSync/ProductValidator.php:422
1031
  msgid "Too many attributes selected for product. Use 4 or less."
1032
  msgstr ""
1033
 
includes/Admin.php CHANGED
@@ -1142,10 +1142,16 @@ class Admin {
1142
  public function add_product_settings_tab_content() {
1143
  global $post;
1144
 
 
1145
  // all products have sync enabled unless explicitly disabled
1146
  $sync_enabled = 'no' !== get_post_meta( $post->ID, Products::SYNC_ENABLED_META_KEY, true );
1147
  $is_visible = ( $visibility = get_post_meta( $post->ID, Products::VISIBILITY_META_KEY, true ) ) ? wc_string_to_bool( $visibility ) : true;
1148
 
 
 
 
 
 
1149
  $description = get_post_meta( $post->ID, \WC_Facebookcommerce_Integration::FB_PRODUCT_DESCRIPTION, true );
1150
  $price = get_post_meta( $post->ID, \WC_Facebook_Product::FB_PRODUCT_PRICE, true );
1151
  $image_source = get_post_meta( $post->ID, Products::PRODUCT_IMAGE_SOURCE_META_KEY, true );
@@ -1240,7 +1246,6 @@ class Admin {
1240
  ?>
1241
  </div>
1242
  <?php
1243
- $product = wc_get_product( $post );
1244
  $commerce_handler = facebook_for_woocommerce()->get_commerce_handler();
1245
  ?>
1246
  <?php if ( $commerce_handler->is_connected() && $commerce_handler->is_available() ) : ?>
1142
  public function add_product_settings_tab_content() {
1143
  global $post;
1144
 
1145
+
1146
  // all products have sync enabled unless explicitly disabled
1147
  $sync_enabled = 'no' !== get_post_meta( $post->ID, Products::SYNC_ENABLED_META_KEY, true );
1148
  $is_visible = ( $visibility = get_post_meta( $post->ID, Products::VISIBILITY_META_KEY, true ) ) ? wc_string_to_bool( $visibility ) : true;
1149
 
1150
+ $product = wc_get_product( $post );
1151
+ if ( $product && ! facebook_for_woocommerce()->get_product_sync_validator( $product )->passes_all_checks() ) {
1152
+ $sync_enabled = false;
1153
+ }
1154
+
1155
  $description = get_post_meta( $post->ID, \WC_Facebookcommerce_Integration::FB_PRODUCT_DESCRIPTION, true );
1156
  $price = get_post_meta( $post->ID, \WC_Facebook_Product::FB_PRODUCT_PRICE, true );
1157
  $image_source = get_post_meta( $post->ID, Products::PRODUCT_IMAGE_SOURCE_META_KEY, true );
1246
  ?>
1247
  </div>
1248
  <?php
 
1249
  $commerce_handler = facebook_for_woocommerce()->get_commerce_handler();
1250
  ?>
1251
  <?php if ( $commerce_handler->is_connected() && $commerce_handler->is_available() ) : ?>
includes/Framework/Utilities/BackgroundJobHandler.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- // phpcs:ignoreFile
3
  /**
4
  * Facebook for WooCommerce.
5
  */
@@ -7,8 +7,9 @@
7
  namespace WooCommerce\Facebook\Framework\Utilities;
8
 
9
  use WooCommerce\Facebook\Framework\Plugin\Compatibility;
 
10
 
11
- defined( 'ABSPATH' ) or exit;
12
 
13
  /**
14
  * SkyVerge WordPress Background Job Handler class
@@ -78,15 +79,15 @@ abstract class BackgroundJobHandler extends AsyncRequest {
78
  * @since 4.8.0
79
  */
80
  protected function add_hooks() {
81
-
82
  // cron healthcheck
83
- add_action( $this->cron_hook_identifier, array( $this, 'handle_cron_healthcheck' ) );
84
- add_filter( 'cron_schedules', array( $this, 'schedule_cron_healthcheck' ) );
 
85
 
86
  // debugging & testing
87
- add_action( "wp_ajax_nopriv_{$this->identifier}_test", array( $this, 'handle_connection_test_response' ) );
88
- add_filter( 'woocommerce_debug_tools', array( $this, 'add_debug_tool' ) );
89
- add_filter( 'gettext', array( $this, 'translate_success_message' ), 10, 3 );
90
  }
91
 
92
 
@@ -97,7 +98,6 @@ abstract class BackgroundJobHandler extends AsyncRequest {
97
  * @return array|\WP_Error
98
  */
99
  public function dispatch() {
100
-
101
  // schedule the cron healthcheck
102
  $this->schedule_event();
103
 
@@ -113,10 +113,9 @@ abstract class BackgroundJobHandler extends AsyncRequest {
113
  *
114
  * @since 4.4.0
115
  *
116
- * @throws \Exception upon error
117
  */
118
  public function maybe_handle() {
119
-
120
  if ( $this->is_process_running() ) {
121
  // background process already running
122
  wp_die();
@@ -127,20 +126,22 @@ abstract class BackgroundJobHandler extends AsyncRequest {
127
  wp_die();
128
  }
129
 
130
- // WC core does 2 things here that can interfere with our nonce check:
131
- // 1. WooCommerce starts a session due to our GET request to dispatch a job
132
- // However, this happens *after* we've generated a nonce without a session (in CRON context)
133
- // 2. it then filters nonces for logged-out users indiscriminately without checking the nonce action; if
134
- // there is a session created (and now the server does have one), it tries to filter every.single.nonce
135
- // for logged-out users to use the customer session ID instead of 0 for user ID. We *want* to check
136
- // against a UID of 0 (since that's how the nonce was created), so we temporarily pause the
137
- // logged-out nonce hijacking before standing aside.
138
- remove_filter( 'nonce_user_logged_out', array( WC()->session, 'nonce_user_logged_out' ) );
 
 
139
 
140
  check_ajax_referer( $this->identifier, 'nonce' );
141
 
142
  // sorry, later nonce users! please play again
143
- add_filter( 'nonce_user_logged_out', array( WC()->session, 'nonce_user_logged_out' ) );
144
 
145
  $this->handle();
146
 
@@ -163,14 +164,19 @@ abstract class BackgroundJobHandler extends AsyncRequest {
163
  $queued = '%"status":"queued"%';
164
  $processing = '%"status":"processing"%';
165
 
166
- $count = $wpdb->get_var( $wpdb->prepare( "
167
- SELECT COUNT(*)
168
- FROM {$wpdb->options}
169
- WHERE option_name LIKE %s
170
- AND ( option_value LIKE %s OR option_value LIKE %s )
171
- ", $key, $queued, $processing ) );
 
 
 
 
 
172
 
173
- return ( $count > 0 ) ? false : true;
174
  }
175
 
176
 
@@ -242,7 +248,6 @@ abstract class BackgroundJobHandler extends AsyncRequest {
242
  * @return bool True if exceeded memory limit, false otherwise
243
  */
244
  protected function memory_exceeded() {
245
-
246
  $memory_limit = $this->get_memory_limit() * 0.9; // 90% of max memory
247
  $current_memory = memory_get_usage( true );
248
  $return = false;
@@ -270,7 +275,6 @@ abstract class BackgroundJobHandler extends AsyncRequest {
270
  * @return int memory limit in bytes
271
  */
272
  protected function get_memory_limit() {
273
-
274
  if ( function_exists( 'ini_get' ) ) {
275
  $memory_limit = ini_get( 'memory_limit' );
276
  } else {
@@ -298,7 +302,6 @@ abstract class BackgroundJobHandler extends AsyncRequest {
298
  * @return bool True, if time limit exceeded, false otherwise
299
  */
300
  protected function time_exceeded() {
301
-
302
  /**
303
  * Filter default time limit for background job execution, defaults to
304
  * 20 seconds
@@ -361,18 +364,24 @@ abstract class BackgroundJobHandler extends AsyncRequest {
361
  $attrs = apply_filters( "{$this->identifier}_new_job_attrs", $attrs, $job_id );
362
 
363
  // ensure a few must-have attributes
364
- $attrs = wp_parse_args( array(
365
- 'id' => $job_id,
366
- 'created_at' => current_time( 'mysql' ),
367
- 'created_by' => get_current_user_id(),
368
- 'status' => 'queued',
369
- ), $attrs );
370
-
371
- $wpdb->insert( $wpdb->options, array(
372
- 'option_name' => "{$this->identifier}_job_{$job_id}",
373
- 'option_value' => json_encode( $attrs ),
374
- 'autoload' => 'no'
375
- ) );
 
 
 
 
 
 
376
 
377
  $job = new \stdClass();
378
 
@@ -411,33 +420,35 @@ abstract class BackgroundJobHandler extends AsyncRequest {
411
  $queued = '%"status":"queued"%';
412
  $processing = '%"status":"processing"%';
413
 
414
- $results = $wpdb->get_var( $wpdb->prepare( "
415
- SELECT option_value
416
- FROM {$wpdb->options}
417
- WHERE option_name LIKE %s
418
- AND ( option_value LIKE %s OR option_value LIKE %s )
419
- ORDER BY option_id ASC
420
- LIMIT 1
421
- ", $key, $queued, $processing ) );
422
-
 
 
 
 
423
  } else {
424
-
425
- $results = $wpdb->get_var( $wpdb->prepare( "
426
- SELECT option_value
427
- FROM {$wpdb->options}
428
- WHERE option_name = %s
429
- ", "{$this->identifier}_job_{$id}" ) );
430
-
 
431
  }
432
 
433
  if ( ! empty( $results ) ) {
434
-
435
  $job = new \stdClass();
436
-
437
  foreach ( json_decode( $results, true ) as $key => $value ) {
438
  $job->{$key} = $value;
439
  }
440
-
441
  } else {
442
  return null;
443
  }
@@ -467,29 +478,28 @@ abstract class BackgroundJobHandler extends AsyncRequest {
467
  * }
468
  * @return \stdClass[]|object[]|null Found jobs or null if none found
469
  */
470
- public function get_jobs( $args = array() ) {
471
  global $wpdb;
472
 
473
- $args = wp_parse_args( $args, array(
474
- 'order' => 'DESC',
475
- 'orderby' => 'option_id',
476
- ) );
 
 
 
477
 
478
- $replacements = array( $this->identifier . '_job_%' );
479
  $status_query = '';
480
 
481
  // prepare status query
482
  if ( ! empty( $args['status'] ) ) {
483
-
484
  $statuses = (array) $args['status'];
485
- $placeholders = array();
486
-
487
  foreach ( $statuses as $status ) {
488
-
489
  $placeholders[] = '%s';
490
  $replacements[] = '%"status":"' . sanitize_key( $status ) . '"%';
491
  }
492
-
493
  $status_query = 'AND ( option_value LIKE ' . implode( ' OR option_value LIKE ', $placeholders ) . ' )';
494
  }
495
 
@@ -498,33 +508,27 @@ abstract class BackgroundJobHandler extends AsyncRequest {
498
  $orderby = sanitize_key( $args['orderby'] );
499
 
500
  // put it all together now
501
- $query = $wpdb->prepare( "
502
- SELECT option_value
503
- FROM {$wpdb->options}
504
- WHERE option_name LIKE %s
505
- {$status_query}
506
- ORDER BY {$orderby} {$order}
507
- ", $replacements );
508
 
 
509
  $results = $wpdb->get_col( $query );
510
 
511
  if ( empty( $results ) ) {
512
  return null;
513
  }
514
 
515
- $jobs = array();
516
-
517
  foreach ( $results as $result ) {
518
-
519
  $job = new \stdClass();
520
-
521
  foreach ( json_decode( $result, true ) as $key => $value ) {
522
  $job->{$key} = $value;
523
  }
524
-
525
  /** This filter is documented above */
526
- $job = apply_filters( "{$this->identifier}_returned_job", $job );
527
-
528
  $jobs[] = $job;
529
  }
530
 
@@ -539,23 +543,18 @@ abstract class BackgroundJobHandler extends AsyncRequest {
539
  *
540
  * @since 4.4.0
541
  *
542
- * @throws \Exception
543
  */
544
  protected function handle() {
545
-
546
  $this->lock_process();
547
 
548
  do {
549
-
550
  // Get next job in the queue
551
  $job = $this->get_job();
552
-
553
  // handle PHP errors from here on out
554
- register_shutdown_function( array( $this, 'handle_shutdown' ), $job );
555
-
556
  // Start processing
557
  $this->process_job( $job );
558
-
559
  } while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty() );
560
 
561
  $this->unlock_process();
@@ -588,12 +587,11 @@ abstract class BackgroundJobHandler extends AsyncRequest {
588
  * @since 4.4.0
589
  *
590
  * @param \stdClass|object $job
591
- * @param int $items_per_batch number of items to process in a single request. Defaults to unlimited.
592
- * @throws \Exception when job data is incorrect
593
  * @return \stdClass $job
594
  */
595
  public function process_job( $job, $items_per_batch = null ) {
596
-
597
  if ( ! $this->start_time ) {
598
  $this->start_time = time();
599
  }
@@ -610,10 +608,12 @@ abstract class BackgroundJobHandler extends AsyncRequest {
610
  $data_key = $this->data_key;
611
 
612
  if ( ! isset( $job->{$data_key} ) ) {
 
613
  throw new \Exception( sprintf( __( 'Job data key "%s" not set', 'facebook-for-woocommerce' ), $data_key ) );
614
  }
615
 
616
  if ( ! is_array( $job->{$data_key} ) ) {
 
617
  throw new \Exception( sprintf( __( 'Job data key "%s" is not an array', 'facebook-for-woocommerce' ), $data_key ) );
618
  }
619
 
@@ -734,7 +734,7 @@ abstract class BackgroundJobHandler extends AsyncRequest {
734
  * @since 4.4.0
735
  *
736
  * @param \stdClass|object|string $job Job instance or ID
737
- * @param string $reason Optional. Reason for failure.
738
  * @return \stdClass|false on failure
739
  */
740
  public function fail_job( $job, $reason = '' ) {
@@ -778,7 +778,7 @@ abstract class BackgroundJobHandler extends AsyncRequest {
778
  if ( ! $job ) {
779
  return false;
780
  }
781
- $wpdb->delete( $wpdb->options, array( 'option_name' => "{$this->identifier}_job_{$job->id}" ) );
782
  /**
783
  * Runs after a job is deleted.
784
  *
@@ -821,10 +821,11 @@ abstract class BackgroundJobHandler extends AsyncRequest {
821
  */
822
  $interval = apply_filters( "{$this->identifier}_cron_interval", $interval );
823
  // adds every 5 minutes to the existing schedules.
824
- $schedules[ $this->identifier . '_cron_interval' ] = array(
825
  'interval' => MINUTE_IN_SECONDS * $interval,
826
- 'display' => sprintf( __( 'Every %d Minutes' ), $interval ),
827
- );
 
828
  return $schedules;
829
  }
830
 
@@ -886,7 +887,7 @@ abstract class BackgroundJobHandler extends AsyncRequest {
886
  *
887
  * @since 4.4.2
888
  *
889
- * @param mixed $item Job data item to iterate over
890
  * @param \stdClass|object $job Job instance
891
  * @return mixed
892
  */
@@ -923,8 +924,8 @@ abstract class BackgroundJobHandler extends AsyncRequest {
923
 
924
  return $wpdb->update(
925
  $wpdb->options,
926
- array( 'option_value' => json_encode( $job ) ),
927
- array( 'option_name' => "{$this->identifier}_job_{$job->id}" )
928
  );
929
  }
930
 
@@ -955,7 +956,6 @@ abstract class BackgroundJobHandler extends AsyncRequest {
955
  * @since 4.8.0
956
  */
957
  public function handle_connection_test_response() {
958
-
959
  echo '[TEST_LOOPBACK]';
960
  exit;
961
  }
@@ -970,14 +970,13 @@ abstract class BackgroundJobHandler extends AsyncRequest {
970
  * @return array
971
  */
972
  public function add_debug_tool( $tools ) {
973
-
974
  // this key is not unique to the plugin to avoid duplicate tools
975
- $tools['sv_wc_background_job_test'] = array(
976
  'name' => __( 'Background Processing Test', 'facebook-for-woocommerce' ),
977
  'button' => __( 'Run Test', 'facebook-for-woocommerce' ),
978
  'desc' => __( 'This tool will test whether your server is capable of processing background jobs.', 'facebook-for-woocommerce' ),
979
- 'callback' => array( $this, 'run_debug_tool' ),
980
- );
981
 
982
  return $tools;
983
  }
@@ -991,13 +990,12 @@ abstract class BackgroundJobHandler extends AsyncRequest {
991
  * @return string
992
  */
993
  public function run_debug_tool() {
994
-
995
  if ( $this->test_connection() ) {
996
  $this->debug_message = esc_html__( 'Success! You should be able to process background jobs.', 'facebook-for-woocommerce' );
997
- $result = true;
998
  } else {
999
  $this->debug_message = esc_html__( 'Could not connect. Please ask your hosting company to ensure your server has loopback connections enabled.', 'facebook-for-woocommerce' );
1000
- $result = false;
1001
  }
1002
 
1003
  return $result;
1
  <?php
2
+
3
  /**
4
  * Facebook for WooCommerce.
5
  */
7
  namespace WooCommerce\Facebook\Framework\Utilities;
8
 
9
  use WooCommerce\Facebook\Framework\Plugin\Compatibility;
10
+ use WooCommerce\Facebook\Framework\Helper;
11
 
12
+ defined( 'ABSPATH' ) || exit;
13
 
14
  /**
15
  * SkyVerge WordPress Background Job Handler class
79
  * @since 4.8.0
80
  */
81
  protected function add_hooks() {
 
82
  // cron healthcheck
83
+ add_action( $this->cron_hook_identifier, [ $this, 'handle_cron_healthcheck' ] );
84
+ /* phpcs:ignore WordPress.WP.CronInterval.ChangeDetected */
85
+ add_filter( 'cron_schedules', [ $this, 'schedule_cron_healthcheck' ] );
86
 
87
  // debugging & testing
88
+ add_action( "wp_ajax_nopriv_{$this->identifier}_test", [ $this, 'handle_connection_test_response' ] );
89
+ add_filter( 'woocommerce_debug_tools', [ $this, 'add_debug_tool' ] );
90
+ add_filter( 'gettext', [ $this, 'translate_success_message' ], 10, 3 );
91
  }
92
 
93
 
98
  * @return array|\WP_Error
99
  */
100
  public function dispatch() {
 
101
  // schedule the cron healthcheck
102
  $this->schedule_event();
103
 
113
  *
114
  * @since 4.4.0
115
  *
116
+ * @throws \Exception Upon error.
117
  */
118
  public function maybe_handle() {
 
119
  if ( $this->is_process_running() ) {
120
  // background process already running
121
  wp_die();
126
  wp_die();
127
  }
128
 
129
+ /*
130
+ * WC core does 2 things here that can interfere with our nonce check:
131
+ * 1. WooCommerce starts a session due to our GET request to dispatch a job
132
+ * However, this happens *after* we've generated a nonce without a session (in CRON context)
133
+ * 2. It then filters nonces for logged-out users indiscriminately without checking the nonce action; if
134
+ * there is a session created (and now the server does have one), it tries to filter every.single.nonce
135
+ * for logged-out users to use the customer session ID instead of 0 for user ID. We *want* to check
136
+ * against a UID of 0 (since that's how the nonce was created), so we temporarily pause the
137
+ * logged-out nonce hijacking before standing aside.
138
+ */
139
+ remove_filter( 'nonce_user_logged_out', [ WC()->session, 'nonce_user_logged_out' ] );
140
 
141
  check_ajax_referer( $this->identifier, 'nonce' );
142
 
143
  // sorry, later nonce users! please play again
144
+ add_filter( 'nonce_user_logged_out', [ WC()->session, 'nonce_user_logged_out' ] );
145
 
146
  $this->handle();
147
 
164
  $queued = '%"status":"queued"%';
165
  $processing = '%"status":"processing"%';
166
 
167
+ $count = $wpdb->get_var(
168
+ $wpdb->prepare(
169
+ "SELECT COUNT(*)
170
+ FROM {$wpdb->options}
171
+ WHERE option_name LIKE %s
172
+ AND ( option_value LIKE %s OR option_value LIKE %s )",
173
+ $key,
174
+ $queued,
175
+ $processing
176
+ )
177
+ );
178
 
179
+ return intval( $count ) === 0;
180
  }
181
 
182
 
248
  * @return bool True if exceeded memory limit, false otherwise
249
  */
250
  protected function memory_exceeded() {
 
251
  $memory_limit = $this->get_memory_limit() * 0.9; // 90% of max memory
252
  $current_memory = memory_get_usage( true );
253
  $return = false;
275
  * @return int memory limit in bytes
276
  */
277
  protected function get_memory_limit() {
 
278
  if ( function_exists( 'ini_get' ) ) {
279
  $memory_limit = ini_get( 'memory_limit' );
280
  } else {
302
  * @return bool True, if time limit exceeded, false otherwise
303
  */
304
  protected function time_exceeded() {
 
305
  /**
306
  * Filter default time limit for background job execution, defaults to
307
  * 20 seconds
364
  $attrs = apply_filters( "{$this->identifier}_new_job_attrs", $attrs, $job_id );
365
 
366
  // ensure a few must-have attributes
367
+ $attrs = wp_parse_args(
368
+ [
369
+ 'id' => $job_id,
370
+ 'created_at' => current_time( 'mysql' ),
371
+ 'created_by' => get_current_user_id(),
372
+ 'status' => 'queued',
373
+ ],
374
+ $attrs
375
+ );
376
+
377
+ $wpdb->insert(
378
+ $wpdb->options,
379
+ [
380
+ 'option_name' => "{$this->identifier}_job_{$job_id}",
381
+ 'option_value' => json_encode( $attrs ),
382
+ 'autoload' => 'no',
383
+ ]
384
+ );
385
 
386
  $job = new \stdClass();
387
 
420
  $queued = '%"status":"queued"%';
421
  $processing = '%"status":"processing"%';
422
 
423
+ $results = $wpdb->get_var(
424
+ $wpdb->prepare(
425
+ "SELECT option_value
426
+ FROM {$wpdb->options}
427
+ WHERE option_name LIKE %s
428
+ AND ( option_value LIKE %s OR option_value LIKE %s )
429
+ ORDER BY option_id ASC
430
+ LIMIT 1",
431
+ $key,
432
+ $queued,
433
+ $processing
434
+ )
435
+ );
436
  } else {
437
+ $results = $wpdb->get_var(
438
+ $wpdb->prepare(
439
+ "SELECT option_value
440
+ FROM {$wpdb->options}
441
+ WHERE option_name = %s",
442
+ "{$this->identifier}_job_{$id}"
443
+ )
444
+ );
445
  }
446
 
447
  if ( ! empty( $results ) ) {
 
448
  $job = new \stdClass();
 
449
  foreach ( json_decode( $results, true ) as $key => $value ) {
450
  $job->{$key} = $value;
451
  }
 
452
  } else {
453
  return null;
454
  }
478
  * }
479
  * @return \stdClass[]|object[]|null Found jobs or null if none found
480
  */
481
+ public function get_jobs( $args = [] ) {
482
  global $wpdb;
483
 
484
+ $args = wp_parse_args(
485
+ $args,
486
+ [
487
+ 'order' => 'DESC',
488
+ 'orderby' => 'option_id',
489
+ ]
490
+ );
491
 
492
+ $replacements = [ $this->identifier . '_job_%' ];
493
  $status_query = '';
494
 
495
  // prepare status query
496
  if ( ! empty( $args['status'] ) ) {
 
497
  $statuses = (array) $args['status'];
498
+ $placeholders = [];
 
499
  foreach ( $statuses as $status ) {
 
500
  $placeholders[] = '%s';
501
  $replacements[] = '%"status":"' . sanitize_key( $status ) . '"%';
502
  }
 
503
  $status_query = 'AND ( option_value LIKE ' . implode( ' OR option_value LIKE ', $placeholders ) . ' )';
504
  }
505
 
508
  $orderby = sanitize_key( $args['orderby'] );
509
 
510
  // put it all together now
511
+ $query = $wpdb->prepare(
512
+ /* phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared */
513
+ "SELECT option_value FROM {$wpdb->options} WHERE option_name LIKE %s {$status_query} ORDER BY {$orderby} {$order}",
514
+ $replacements
515
+ );
 
 
516
 
517
+ /* phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared */
518
  $results = $wpdb->get_col( $query );
519
 
520
  if ( empty( $results ) ) {
521
  return null;
522
  }
523
 
524
+ $jobs = [];
 
525
  foreach ( $results as $result ) {
 
526
  $job = new \stdClass();
 
527
  foreach ( json_decode( $result, true ) as $key => $value ) {
528
  $job->{$key} = $value;
529
  }
 
530
  /** This filter is documented above */
531
+ $job = apply_filters( "{$this->identifier}_returned_job", $job );
 
532
  $jobs[] = $job;
533
  }
534
 
543
  *
544
  * @since 4.4.0
545
  *
546
+ * @throws \Exception Upon error.
547
  */
548
  protected function handle() {
 
549
  $this->lock_process();
550
 
551
  do {
 
552
  // Get next job in the queue
553
  $job = $this->get_job();
 
554
  // handle PHP errors from here on out
555
+ register_shutdown_function( [ $this, 'handle_shutdown' ], $job );
 
556
  // Start processing
557
  $this->process_job( $job );
 
558
  } while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty() );
559
 
560
  $this->unlock_process();
587
  * @since 4.4.0
588
  *
589
  * @param \stdClass|object $job
590
+ * @param int $items_per_batch number of items to process in a single request. Defaults to unlimited.
591
+ * @throws \Exception When job data is incorrect.
592
  * @return \stdClass $job
593
  */
594
  public function process_job( $job, $items_per_batch = null ) {
 
595
  if ( ! $this->start_time ) {
596
  $this->start_time = time();
597
  }
608
  $data_key = $this->data_key;
609
 
610
  if ( ! isset( $job->{$data_key} ) ) {
611
+ /* translators: %s - string representing data key. */
612
  throw new \Exception( sprintf( __( 'Job data key "%s" not set', 'facebook-for-woocommerce' ), $data_key ) );
613
  }
614
 
615
  if ( ! is_array( $job->{$data_key} ) ) {
616
+ /* translators: %s - string representing data key. */
617
  throw new \Exception( sprintf( __( 'Job data key "%s" is not an array', 'facebook-for-woocommerce' ), $data_key ) );
618
  }
619
 
734
  * @since 4.4.0
735
  *
736
  * @param \stdClass|object|string $job Job instance or ID
737
+ * @param string $reason Optional. Reason for failure.
738
  * @return \stdClass|false on failure
739
  */
740
  public function fail_job( $job, $reason = '' ) {
778
  if ( ! $job ) {
779
  return false;
780
  }
781
+ $wpdb->delete( $wpdb->options, [ 'option_name' => "{$this->identifier}_job_{$job->id}" ] );
782
  /**
783
  * Runs after a job is deleted.
784
  *
821
  */
822
  $interval = apply_filters( "{$this->identifier}_cron_interval", $interval );
823
  // adds every 5 minutes to the existing schedules.
824
+ $schedules[ $this->identifier . '_cron_interval' ] = [
825
  'interval' => MINUTE_IN_SECONDS * $interval,
826
+ /* translators: %d - interval in minutes. */
827
+ 'display' => sprintf( __( 'Every %d Minutes', 'facebook-for-woocommerce' ), $interval ),
828
+ ];
829
  return $schedules;
830
  }
831
 
887
  *
888
  * @since 4.4.2
889
  *
890
+ * @param mixed $item Job data item to iterate over
891
  * @param \stdClass|object $job Job instance
892
  * @return mixed
893
  */
924
 
925
  return $wpdb->update(
926
  $wpdb->options,
927
+ [ 'option_value' => json_encode( $job ) ],
928
+ [ 'option_name' => "{$this->identifier}_job_{$job->id}" ]
929
  );
930
  }
931
 
956
  * @since 4.8.0
957
  */
958
  public function handle_connection_test_response() {
 
959
  echo '[TEST_LOOPBACK]';
960
  exit;
961
  }
970
  * @return array
971
  */
972
  public function add_debug_tool( $tools ) {
 
973
  // this key is not unique to the plugin to avoid duplicate tools
974
+ $tools['sv_wc_background_job_test'] = [
975
  'name' => __( 'Background Processing Test', 'facebook-for-woocommerce' ),
976
  'button' => __( 'Run Test', 'facebook-for-woocommerce' ),
977
  'desc' => __( 'This tool will test whether your server is capable of processing background jobs.', 'facebook-for-woocommerce' ),
978
+ 'callback' => [ $this, 'run_debug_tool' ],
979
+ ];
980
 
981
  return $tools;
982
  }
990
  * @return string
991
  */
992
  public function run_debug_tool() {
 
993
  if ( $this->test_connection() ) {
994
  $this->debug_message = esc_html__( 'Success! You should be able to process background jobs.', 'facebook-for-woocommerce' );
995
+ $result = true;
996
  } else {
997
  $this->debug_message = esc_html__( 'Could not connect. Please ask your hosting company to ensure your server has loopback connections enabled.', 'facebook-for-woocommerce' );
998
+ $result = false;
999
  }
1000
 
1001
  return $result;
includes/ProductSync/ProductValidator.php CHANGED
@@ -135,6 +135,22 @@ class ProductValidator {
135
  $this->validate_product_title();
136
  }
137
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  /**
139
  * Validate whether the product should be synced to Facebook.
140
  *
@@ -186,6 +202,23 @@ class ProductValidator {
186
  return true;
187
  }
188
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  /**
190
  * Check whether product sync is globally disabled.
191
  *
135
  $this->validate_product_title();
136
  }
137
 
138
+ /**
139
+ * Validate whether the product should be synced to Facebook but skip the sync field check.
140
+ *
141
+ * @since 3.0.6
142
+ * @throws ProductExcludedException|ProductInvalidException If product should not be synced.
143
+ */
144
+ public function validate_but_skip_sync_field() {
145
+ $this->validate_sync_enabled_globally();
146
+ $this->validate_product_stock_status();
147
+ $this->validate_product_price();
148
+ $this->validate_product_visibility();
149
+ $this->validate_product_terms();
150
+ $this->validate_product_description();
151
+ $this->validate_product_title();
152
+ }
153
+
154
  /**
155
  * Validate whether the product should be synced to Facebook.
156
  *
202
  return true;
203
  }
204
 
205
+ /**
206
+ * Validate whether the product should be synced to Facebook, but skip the sync field validation.
207
+ *
208
+ * @return bool
209
+ */
210
+ public function passes_all_checks_except_sync_field(): bool {
211
+ try {
212
+ $this->validate_but_skip_sync_field();
213
+ } catch ( ProductExcludedException $e ) {
214
+ return false;
215
+ } catch ( ProductInvalidException $e ) {
216
+ return false;
217
+ }
218
+
219
+ return true;
220
+ }
221
+
222
  /**
223
  * Check whether product sync is globally disabled.
224
  *
includes/Utilities/Tracker.php CHANGED
@@ -161,8 +161,8 @@ class Tracker {
161
  * @since 2.6.0
162
  */
163
  $config = get_transient( self::TRANSIENT_WCTRACKER_FBE_BUSINESS_CONFIG );
164
- $data['extensions']['facebook-for-woocommerce']['instagram-shopping-enabled'] = wc_bool_to_string( $config ? $config->ig_shopping_enabled : false );
165
- $data['extensions']['facebook-for-woocommerce']['instagram-cta-enabled'] = wc_bool_to_string( $config ? $config->ig_cta_enabled : false );
166
 
167
  /**
168
  * Feed pull / upload settings configured in Facebook UI.
161
  * @since 2.6.0
162
  */
163
  $config = get_transient( self::TRANSIENT_WCTRACKER_FBE_BUSINESS_CONFIG );
164
+ $data['extensions']['facebook-for-woocommerce']['instagram-shopping-enabled'] = wc_bool_to_string( $config ? $config['ig_shopping_enabled'] : false );
165
+ $data['extensions']['facebook-for-woocommerce']['instagram-cta-enabled'] = wc_bool_to_string( $config ? $config['ig_cta_enabled'] : false );
166
 
167
  /**
168
  * Feed pull / upload settings configured in Facebook UI.
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: 6.1
6
- Stable tag: 3.0.5
7
  Requires PHP: 5.6 or greater
8
  MySQL: 5.6 or greater
9
  License: GPLv2 or later
@@ -39,6 +39,14 @@ When opening a bug on GitHub, please give us as many details as possible.
39
 
40
  == Changelog ==
41
 
 
 
 
 
 
 
 
 
42
  = 3.0.5 - 2022-11-30 =
43
  * Add - Debug tools to help reset settings, delete background options and delete catalog products.
44
  * Add - Inbox note about Facebook menu moved under the Marketing menu.
3
  Tags: facebook, shop, catalog, advertise, pixel, product
4
  Requires at least: 4.4
5
  Tested up to: 6.1
6
+ Stable tag: 3.0.6
7
  Requires PHP: 5.6 or greater
8
  MySQL: 5.6 or greater
9
  License: GPLv2 or later
39
 
40
  == Changelog ==
41
 
42
+ = 3.0.6 - 2022-12-13 =
43
+ * Dev - Add node and npm version restrictions.
44
+ * Fix - PHP Warning: Attempt to read property on array in Tracker.php.
45
+ * Fix - Deprecated notice fix.
46
+ * Fix - Facebook Sync status is incorrect when a product has catalog visibility hidden.
47
+ * Fix - Issue in running Background Process Test debug tool.
48
+ * Tweak - WC 7.2 compatibility.
49
+
50
  = 3.0.5 - 2022-11-30 =
51
  * Add - Debug tools to help reset settings, delete background options and delete catalog products.
52
  * Add - Inbox note about Facebook menu moved under the Marketing menu.
vendor/autoload.php CHANGED
@@ -9,4 +9,4 @@ if (PHP_VERSION_ID < 50600) {
9
 
10
  require_once __DIR__ . '/composer/autoload_real.php';
11
 
12
- return ComposerAutoloaderInitea9949fe138c408a8667af28726c644c::getLoader();
9
 
10
  require_once __DIR__ . '/composer/autoload_real.php';
11
 
12
+ return ComposerAutoloaderInit715cd99f3c6171fe42bfa6c3e60481f7::getLoader();
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInitea9949fe138c408a8667af28726c644c
6
  {
7
  private static $loader;
8
 
@@ -24,12 +24,12 @@ class ComposerAutoloaderInitea9949fe138c408a8667af28726c644c
24
 
25
  require __DIR__ . '/platform_check.php';
26
 
27
- spl_autoload_register(array('ComposerAutoloaderInitea9949fe138c408a8667af28726c644c', 'loadClassLoader'), true, true);
28
  self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
29
- spl_autoload_unregister(array('ComposerAutoloaderInitea9949fe138c408a8667af28726c644c', 'loadClassLoader'));
30
 
31
  require __DIR__ . '/autoload_static.php';
32
- call_user_func(\Composer\Autoload\ComposerStaticInitea9949fe138c408a8667af28726c644c::getInitializer($loader));
33
 
34
  $loader->register(true);
35
 
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit715cd99f3c6171fe42bfa6c3e60481f7
6
  {
7
  private static $loader;
8
 
24
 
25
  require __DIR__ . '/platform_check.php';
26
 
27
+ spl_autoload_register(array('ComposerAutoloaderInit715cd99f3c6171fe42bfa6c3e60481f7', 'loadClassLoader'), true, true);
28
  self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
29
+ spl_autoload_unregister(array('ComposerAutoloaderInit715cd99f3c6171fe42bfa6c3e60481f7', 'loadClassLoader'));
30
 
31
  require __DIR__ . '/autoload_static.php';
32
+ call_user_func(\Composer\Autoload\ComposerStaticInit715cd99f3c6171fe42bfa6c3e60481f7::getInitializer($loader));
33
 
34
  $loader->register(true);
35
 
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInitea9949fe138c408a8667af28726c644c
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'W' =>
@@ -293,9 +293,9 @@ class ComposerStaticInitea9949fe138c408a8667af28726c644c
293
  public static function getInitializer(ClassLoader $loader)
294
  {
295
  return \Closure::bind(function () use ($loader) {
296
- $loader->prefixLengthsPsr4 = ComposerStaticInitea9949fe138c408a8667af28726c644c::$prefixLengthsPsr4;
297
- $loader->prefixDirsPsr4 = ComposerStaticInitea9949fe138c408a8667af28726c644c::$prefixDirsPsr4;
298
- $loader->classMap = ComposerStaticInitea9949fe138c408a8667af28726c644c::$classMap;
299
 
300
  }, null, ClassLoader::class);
301
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit715cd99f3c6171fe42bfa6c3e60481f7
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'W' =>
293
  public static function getInitializer(ClassLoader $loader)
294
  {
295
  return \Closure::bind(function () use ($loader) {
296
+ $loader->prefixLengthsPsr4 = ComposerStaticInit715cd99f3c6171fe42bfa6c3e60481f7::$prefixLengthsPsr4;
297
+ $loader->prefixDirsPsr4 = ComposerStaticInit715cd99f3c6171fe42bfa6c3e60481f7::$prefixDirsPsr4;
298
+ $loader->classMap = ComposerStaticInit715cd99f3c6171fe42bfa6c3e60481f7::$classMap;
299
 
300
  }, null, ClassLoader::class);
301
  }
vendor/composer/installed.php CHANGED
@@ -1,9 +1,9 @@
1
  <?php return array(
2
  'root' => array(
3
  'name' => 'facebookincubator/facebook-for-woocommerce',
4
- 'pretty_version' => 'dev-release/3.0.5',
5
- 'version' => 'dev-release/3.0.5',
6
- 'reference' => 'a1efe7edf48cfc49e4f5a236ca16f0c7f71358b0',
7
  'type' => 'wordpress-plugin',
8
  'install_path' => __DIR__ . '/../../',
9
  'aliases' => array(),
@@ -20,9 +20,9 @@
20
  'dev_requirement' => false,
21
  ),
22
  'facebookincubator/facebook-for-woocommerce' => array(
23
- 'pretty_version' => 'dev-release/3.0.5',
24
- 'version' => 'dev-release/3.0.5',
25
- 'reference' => 'a1efe7edf48cfc49e4f5a236ca16f0c7f71358b0',
26
  'type' => 'wordpress-plugin',
27
  'install_path' => __DIR__ . '/../../',
28
  'aliases' => array(),
1
  <?php return array(
2
  'root' => array(
3
  'name' => 'facebookincubator/facebook-for-woocommerce',
4
+ 'pretty_version' => 'dev-release/3.0.6',
5
+ 'version' => 'dev-release/3.0.6',
6
+ 'reference' => '25a31ad8111acf52d79746d42758cdea07788368',
7
  'type' => 'wordpress-plugin',
8
  'install_path' => __DIR__ . '/../../',
9
  'aliases' => array(),
20
  'dev_requirement' => false,
21
  ),
22
  'facebookincubator/facebook-for-woocommerce' => array(
23
+ 'pretty_version' => 'dev-release/3.0.6',
24
+ 'version' => 'dev-release/3.0.6',
25
+ 'reference' => '25a31ad8111acf52d79746d42758cdea07788368',
26
  'type' => 'wordpress-plugin',
27
  'install_path' => __DIR__ . '/../../',
28
  'aliases' => array(),