Version Description
- 2021-06-10 =
- Fix Add cron heartbeat and use to offload feed generation from init / admin_init (performance) #1953
- Fix Clean up background sync options (performance) #1962
- Dev Add tracker props to understand usage of feed-based sync and other FB business config options #1972
- Dev Configure release tooling to auto-update version numbers in code #1982
- Dev Refactor code responsible for validating whether a product should be synced to FB into one place #19333
Download this release
Release Info
Developer | automattic |
Plugin | Facebook for WooCommerce |
Version | 2.6.0 |
Comparing to | |
See all releases |
Code changes from version 2.5.1 to 2.6.0
- assets/build/admin/google-product-category-fields.asset.php +1 -1
- assets/build/admin/google-product-category-fields.js +1 -1
- changelog.txt +8 -1
- class-wc-facebookcommerce.php +32 -0
- facebook-commerce-events-tracker.php +2 -4
- facebook-commerce.php +19 -17
- facebook-for-woocommerce.php +3 -3
- i18n/languages/facebook-for-woocommerce.pot +81 -49
- includes/AJAX.php +1 -4
- includes/API/FBE/Configuration/Read/Response.php +35 -0
- includes/Feed/FeedConfigurationDetection.php +210 -0
- includes/Handlers/Connection.php +17 -23
- includes/Jobs/CleanupSkyvergeFrameworkJobOptions.php +60 -0
- includes/Jobs/JobRegistry.php +8 -0
- includes/ProductSync/ProductExcludedException.php +12 -0
- includes/ProductSync/ProductValidator.php +259 -0
- includes/Products.php +19 -80
- includes/Products/Feed.php +3 -1
- includes/Utilities/Heartbeat.php +95 -0
- includes/Utilities/Tracker.php +131 -5
- includes/fbgraph.php +69 -0
- includes/fbproductfeed.php +4 -0
- readme.txt +10 -3
- vendor/autoload.php +1 -1
- vendor/composer/autoload_real.php +4 -4
- vendor/composer/autoload_static.php +3 -3
assets/build/admin/google-product-category-fields.asset.php
CHANGED
@@ -1 +1 @@
|
|
1 |
-
<?php return array('dependencies' => array('wp-polyfill'), 'version' => '
|
1 |
+
<?php return array('dependencies' => array('wp-polyfill'), 'version' => '626147500c00fb1fe6128015d31a1369');
|
assets/build/admin/google-product-category-fields.js
CHANGED
@@ -1 +1 @@
|
|
1 |
-
!function(e){var t={};function o(a){if(t[a])return t[a].exports;var
|
1 |
+
!function(e){var t={};function o(a){if(t[a])return t[a].exports;var r=t[a]={i:a,l:!1,exports:{}};return e[a].call(r.exports,r,r.exports,o),r.l=!0,r.exports}o.m=e,o.c=t,o.d=function(e,t,a){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:a})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,t){if(1&t&&(e=o(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var a=Object.create(null);if(o.r(a),Object.defineProperty(a,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)o.d(a,r,function(t){return e[t]}.bind(null,r));return a},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o(o.s=3)}([function(e,t){e.exports=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t){function o(e,t){for(var o=0;o<t.length;o++){var a=t[o];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,a.key,a)}}e.exports=function(e,t,a){return t&&o(e.prototype,t),a&&o(e,a),e},e.exports.default=e.exports,e.exports.__esModule=!0},,function(e,t,o){"use strict";o.r(t);var a=o(0),r=o.n(a),n=o(1),c=o.n(n);jQuery(document).ready((function(e){window.WC_Facebook_Google_Product_Category_Fields=function(){function t(o,a){var n=this;r()(this,t),this.categories=o,this.input_id=a;var c=e("#"+this.input_id);e('<div id="wc-facebook-google-product-category-fields"></div>').insertBefore(c).on("change","select.wc-facebook-google-product-category-select",(function(t){n.onChange(e(t.target))})),this.addInitialSelects(c.val());var i=this.globalsHolder().enhanced_attribute_optional_selector;void 0!==i&&e("#"+i).on("change",(function(){e(".wc-facebook-enhanced-catalog-attribute-optional-row").toggleClass("hidden",!e(this).prop("checked"))}))}return c()(t,[{key:"globalsHolder",value:function(){return"undefined"!=typeof facebook_for_woocommerce_product_categories?facebook_for_woocommerce_product_categories:"undefined"!=typeof facebook_for_woocommerce_settings_sync?facebook_for_woocommerce_settings_sync:facebook_for_woocommerce_products_admin}},{key:"getPageType",value:function(){return"undefined"!=typeof facebook_for_woocommerce_product_categories?0===e("input[name=tag_ID]").length?this.globalsHolder().enhanced_attribute_page_type_add_category:this.globalsHolder().enhanced_attribute_page_type_edit_category:this.globalsHolder().enhanced_attribute_page_type_edit_product}},{key:"addInitialSelects",value:function(e){var t=this;if(e){this.getSelectedCategoryIds(e).forEach((function(e){t.addSelect(t.getOptions(e[1]),e[0])}));var o=this.getOptions(e);Object.keys(o).length&&this.addSelect(o)}else this.addSelect(this.getOptions()),this.addSelect({})}},{key:"requestAttributesIfValid",value:function(){if("true"===e("#wc_facebook_can_show_enhanced_catalog_attributes_id").val()&&(e(".wc-facebook-enhanced-catalog-attribute-row").remove(),this.isValid())){var t="#"+this.input_id,o=e(t).parents("div.form-field"),a=this.globalsHolder().enhanced_attribute_optional_selector;this.getPageType()===this.globalsHolder().enhanced_attribute_page_type_edit_category?o=e(t).parents("tr.form-field"):this.getPageType()===this.globalsHolder().enhanced_attribute_page_type_edit_product&&(o=e(t).parents("p.form-field")),e.get(this.globalsHolder().ajax_url,{action:"wc_facebook_enhanced_catalog_attributes",security:"",selected_category:e(t).val(),tag_id:parseInt(e("input[name=tag_ID]").val(),10),taxonomy:e("input[name=taxonomy]").val(),item_id:parseInt(e("input[name=post_ID]").val(),10),page_type:this.getPageType()},(function(t){var r=e(t);e("#"+a,r).on("change",(function(){e(".wc-facebook-enhanced-catalog-attribute-optional-row").toggleClass("hidden",!e(this).prop("checked"))})),r.insertAfter(o),e(document.body).trigger("init_tooltips")}))}}},{key:"onChange",value:function(t){t.hasClass("locked")&&t.closest(".wc-facebook-google-product-category-field").nextAll().remove();var o=t.val();if(o){var a=this.getOptions(o);Object.keys(a).length&&this.addSelect(a)}else(o=t.closest("#wc-facebook-google-product-category-fields").find(".wc-facebook-google-product-category-select").not(t).last().val())||this.addSelect({});e("#"+this.input_id).val(o),this.requestAttributesIfValid()}},{key:"isValid",value:function(){return e(".wc-facebook-google-product-category-select").filter((function(t,o){return""!==e(o).val()})).length>=2}},{key:"addSelect",value:function(t,o){var a=e("#wc-facebook-google-product-category-fields"),r=a.find(".wc-facebook-google-product-category-select"),n=e('<select class="wc-enhanced-select wc-facebook-google-product-category-select"></select>');r.addClass("locked"),a.append(e('<div class="wc-facebook-google-product-category-field" style="margin-bottom: 16px">').append(n)),n.attr("data-placeholder",this.getSelectPlaceholder(r,t)).append(e('<option value=""></option>')),Object.keys(t).forEach((function(o){n.append(e('<option value="'+o+'">'+t[o]+"</option>"))})),n.val(o).select2({allowClear:!0})}},{key:"getSelectPlaceholder",value:function(e,t){return 0===e.length?facebook_for_woocommerce_google_product_category.i18n.top_level_dropdown_placeholder:1===e.length&&0===Object.keys(t).length?facebook_for_woocommerce_google_product_category.i18n.second_level_empty_dropdown_placeholder:facebook_for_woocommerce_google_product_category.i18n.general_dropdown_placeholder}},{key:"getOptions",value:function(e){return void 0===e||""===e?this.getTopLevelOptions():void 0===this.categories[e]||void 0===this.categories[e].options?[]:this.categories[e].options}},{key:"getTopLevelOptions",value:function(){var e=this,t={};return Object.keys(this.categories).forEach((function(o){e.categories[o].parent||(t[o]=e.categories[o].label)})),t}},{key:"getSelectedCategoryIds",value:function(e){var t=[];do{void 0!==this.categories[e]&&(t.push([e,this.categories[e].parent]),e=this.categories[e].parent)}while(""!==e);return t.reverse()}}]),t}()}))}]);
|
changelog.txt
CHANGED
@@ -1,6 +1,13 @@
|
|
1 |
*** Facebook for WooCommerce Changelog ***
|
2 |
|
3 |
-
2021-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
* Fix - Reinstate reset and delete functions in Facebook metabox on Edit product admin screen #1980
|
5 |
|
6 |
2021-05-19 - version 2.5.0
|
1 |
*** Facebook for WooCommerce Changelog ***
|
2 |
|
3 |
+
2021-06-10 - version 2.6.0
|
4 |
+
* Fix – Add cron heartbeat and use to offload feed generation from init / admin_init (performance) #1953
|
5 |
+
* Fix – Clean up background sync options (performance) #1962
|
6 |
+
* Dev – Add tracker props to understand usage of feed-based sync and other FB business config options #1972
|
7 |
+
* Dev – Configure release tooling to auto-update version numbers in code #1982
|
8 |
+
* Dev – Refactor code responsible for validating whether a product should be synced to FB into one place #19333
|
9 |
+
|
10 |
+
2021-05-28 - version 2.5.1
|
11 |
* Fix - Reinstate reset and delete functions in Facebook metabox on Edit product admin screen #1980
|
12 |
|
13 |
2021-05-19 - version 2.5.0
|
class-wc-facebookcommerce.php
CHANGED
@@ -13,6 +13,8 @@ use SkyVerge\WooCommerce\Facebook\Lifecycle;
|
|
13 |
use SkyVerge\WooCommerce\Facebook\Utilities\Background_Handle_Virtual_Products_Variations;
|
14 |
use SkyVerge\WooCommerce\Facebook\Utilities\Background_Remove_Duplicate_Visibility_Meta;
|
15 |
use SkyVerge\WooCommerce\PluginFramework\v5_10_0 as Framework;
|
|
|
|
|
16 |
|
17 |
if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
|
18 |
|
@@ -94,6 +96,9 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
|
|
94 |
/** @var \SkyVerge\WooCommerce\Facebook\Jobs\JobRegistry */
|
95 |
public $job_registry;
|
96 |
|
|
|
|
|
|
|
97 |
/**
|
98 |
* Constructs the plugin.
|
99 |
*
|
@@ -142,10 +147,14 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
|
|
142 |
require_once __DIR__ . '/facebook-commerce-messenger-chat.php';
|
143 |
require_once __DIR__ . '/includes/Exceptions/ConnectWCAPIException.php';
|
144 |
|
|
|
|
|
|
|
145 |
$this->product_feed = new \SkyVerge\WooCommerce\Facebook\Products\Feed();
|
146 |
$this->products_stock_handler = new \SkyVerge\WooCommerce\Facebook\Products\Stock();
|
147 |
$this->products_sync_handler = new \SkyVerge\WooCommerce\Facebook\Products\Sync();
|
148 |
$this->sync_background_handler = new \SkyVerge\WooCommerce\Facebook\Products\Sync\Background();
|
|
|
149 |
$this->product_sets_sync_handler = new \SkyVerge\WooCommerce\Facebook\ProductSets\Sync();
|
150 |
$this->commerce_handler = new \SkyVerge\WooCommerce\Facebook\Commerce();
|
151 |
$this->fb_categories = new \SkyVerge\WooCommerce\Facebook\Products\FBCategories();
|
@@ -909,6 +918,18 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
|
|
909 |
return $this->commerce_handler;
|
910 |
}
|
911 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
912 |
/**
|
913 |
* Gets the debug profiling logger instance.
|
914 |
*
|
@@ -924,6 +945,17 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
|
|
924 |
return $instance;
|
925 |
}
|
926 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
927 |
/**
|
928 |
* Gets the settings page URL.
|
929 |
*
|
13 |
use SkyVerge\WooCommerce\Facebook\Utilities\Background_Handle_Virtual_Products_Variations;
|
14 |
use SkyVerge\WooCommerce\Facebook\Utilities\Background_Remove_Duplicate_Visibility_Meta;
|
15 |
use SkyVerge\WooCommerce\PluginFramework\v5_10_0 as Framework;
|
16 |
+
use SkyVerge\WooCommerce\Facebook\ProductSync\ProductValidator as ProductSyncValidator;
|
17 |
+
use SkyVerge\WooCommerce\Facebook\Utilities\Heartbeat;
|
18 |
|
19 |
if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
|
20 |
|
96 |
/** @var \SkyVerge\WooCommerce\Facebook\Jobs\JobRegistry */
|
97 |
public $job_registry;
|
98 |
|
99 |
+
/** @var Heartbeat */
|
100 |
+
public $heartbeat;
|
101 |
+
|
102 |
/**
|
103 |
* Constructs the plugin.
|
104 |
*
|
147 |
require_once __DIR__ . '/facebook-commerce-messenger-chat.php';
|
148 |
require_once __DIR__ . '/includes/Exceptions/ConnectWCAPIException.php';
|
149 |
|
150 |
+
$this->heartbeat = new Heartbeat( WC()->queue() );
|
151 |
+
$this->heartbeat->init();
|
152 |
+
|
153 |
$this->product_feed = new \SkyVerge\WooCommerce\Facebook\Products\Feed();
|
154 |
$this->products_stock_handler = new \SkyVerge\WooCommerce\Facebook\Products\Stock();
|
155 |
$this->products_sync_handler = new \SkyVerge\WooCommerce\Facebook\Products\Sync();
|
156 |
$this->sync_background_handler = new \SkyVerge\WooCommerce\Facebook\Products\Sync\Background();
|
157 |
+
$this->configuration_detection = new \SkyVerge\WooCommerce\Facebook\Feed\FeedConfigurationDetection();
|
158 |
$this->product_sets_sync_handler = new \SkyVerge\WooCommerce\Facebook\ProductSets\Sync();
|
159 |
$this->commerce_handler = new \SkyVerge\WooCommerce\Facebook\Commerce();
|
160 |
$this->fb_categories = new \SkyVerge\WooCommerce\Facebook\Products\FBCategories();
|
918 |
return $this->commerce_handler;
|
919 |
}
|
920 |
|
921 |
+
/**
|
922 |
+
* Gets tracker instance.
|
923 |
+
*
|
924 |
+
* @since 2.6.0
|
925 |
+
*
|
926 |
+
* @return \SkyVerge\WooCommerce\Facebook\Utilities\Tracker
|
927 |
+
*/
|
928 |
+
public function get_tracker() {
|
929 |
+
|
930 |
+
return $this->tracker;
|
931 |
+
}
|
932 |
+
|
933 |
/**
|
934 |
* Gets the debug profiling logger instance.
|
935 |
*
|
945 |
return $instance;
|
946 |
}
|
947 |
|
948 |
+
/**
|
949 |
+
* Get the product sync validator class.
|
950 |
+
*
|
951 |
+
* @param WC_Product $product A product object to be validated.
|
952 |
+
*
|
953 |
+
* @return ProductSyncValidator
|
954 |
+
*/
|
955 |
+
public function get_product_sync_validator( WC_Product $product ) {
|
956 |
+
return new ProductSyncValidator( $this->get_integration(), $product );
|
957 |
+
}
|
958 |
+
|
959 |
/**
|
960 |
* Gets the settings page URL.
|
961 |
*
|
facebook-commerce-events-tracker.php
CHANGED
@@ -1036,10 +1036,8 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
|
|
1036 |
} catch ( Framework\SV_WC_API_Exception $exception ) {
|
1037 |
|
1038 |
$success = false;
|
1039 |
-
|
1040 |
-
|
1041 |
-
facebook_for_woocommerce()->log( 'Could not send Pixel event: ' . $exception->getMessage() );
|
1042 |
-
}
|
1043 |
}
|
1044 |
|
1045 |
return $success;
|
1036 |
} catch ( Framework\SV_WC_API_Exception $exception ) {
|
1037 |
|
1038 |
$success = false;
|
1039 |
+
|
1040 |
+
facebook_for_woocommerce()->log( 'Could not send Pixel event: ' . $exception->getMessage() );
|
|
|
|
|
1041 |
}
|
1042 |
|
1043 |
return $success;
|
facebook-commerce.php
CHANGED
@@ -137,6 +137,8 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
|
|
137 |
/** @var array the page name and url */
|
138 |
private $page;
|
139 |
|
|
|
|
|
140 |
|
141 |
/** Legacy properties *********************************************************************************************/
|
142 |
|
@@ -685,6 +687,16 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
|
|
685 |
<?php
|
686 |
}
|
687 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
688 |
|
689 |
/**
|
690 |
* Gets a list of Product Item IDs indexed by the ID of the variation.
|
@@ -1192,10 +1204,6 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
|
|
1192 |
|
1193 |
$product = wc_get_product( $product_id );
|
1194 |
|
1195 |
-
if ( ! $this->product_should_be_synced( $product ) ) {
|
1196 |
-
return;
|
1197 |
-
}
|
1198 |
-
|
1199 |
if ( $product->is_type( 'variable' ) ) {
|
1200 |
$this->on_variable_product_publish( $product_id );
|
1201 |
} else {
|
@@ -1343,25 +1351,19 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
|
|
1343 |
/**
|
1344 |
* Determines whether the product with the given ID should be synced.
|
1345 |
*
|
|
|
|
|
1346 |
* @since 2.0.0
|
1347 |
*
|
1348 |
* @param \WC_Product|false $product product object
|
1349 |
*/
|
1350 |
public function product_should_be_synced( $product ) {
|
1351 |
-
|
1352 |
-
|
1353 |
-
|
1354 |
-
|
1355 |
-
|
1356 |
-
$should_be_synced = false;
|
1357 |
-
}
|
1358 |
-
|
1359 |
-
// make sure the given product is enabled for sync
|
1360 |
-
if ( $should_be_synced && ! Products::product_should_be_synced( $product ) ) {
|
1361 |
-
$should_be_synced = false;
|
1362 |
}
|
1363 |
-
|
1364 |
-
return $should_be_synced;
|
1365 |
}
|
1366 |
|
1367 |
|
137 |
/** @var array the page name and url */
|
138 |
private $page;
|
139 |
|
140 |
+
/** @var WC_Facebookcommerce_Graph_API API handling class. */
|
141 |
+
private $fbgraph;
|
142 |
|
143 |
/** Legacy properties *********************************************************************************************/
|
144 |
|
687 |
<?php
|
688 |
}
|
689 |
|
690 |
+
/**
|
691 |
+
* Returns graph API client object.
|
692 |
+
*
|
693 |
+
* @since 2.6.0
|
694 |
+
*
|
695 |
+
* @return WC_Facebookcommerce_Graph_API
|
696 |
+
*/
|
697 |
+
public function get_graph_api() {
|
698 |
+
return $this->fbgraph;
|
699 |
+
}
|
700 |
|
701 |
/**
|
702 |
* Gets a list of Product Item IDs indexed by the ID of the variation.
|
1204 |
|
1205 |
$product = wc_get_product( $product_id );
|
1206 |
|
|
|
|
|
|
|
|
|
1207 |
if ( $product->is_type( 'variable' ) ) {
|
1208 |
$this->on_variable_product_publish( $product_id );
|
1209 |
} else {
|
1351 |
/**
|
1352 |
* Determines whether the product with the given ID should be synced.
|
1353 |
*
|
1354 |
+
* @deprecated use \SkyVerge\WooCommerce\Facebook\ProductSync\ProductValidator::validate instead
|
1355 |
+
*
|
1356 |
* @since 2.0.0
|
1357 |
*
|
1358 |
* @param \WC_Product|false $product product object
|
1359 |
*/
|
1360 |
public function product_should_be_synced( $product ) {
|
1361 |
+
try {
|
1362 |
+
facebook_for_woocommerce()->get_product_sync_validator( $product )->validate();
|
1363 |
+
return true;
|
1364 |
+
} catch ( \Exception $e ) {
|
1365 |
+
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
1366 |
}
|
|
|
|
|
1367 |
}
|
1368 |
|
1369 |
|
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.
|
14 |
* Text Domain: facebook-for-woocommerce
|
15 |
* WC requires at least: 3.5.0
|
16 |
-
* WC tested up to: 5.
|
17 |
* Requires PHP: 7.0
|
18 |
*
|
19 |
* @package FacebookCommerce
|
@@ -31,7 +31,7 @@ class WC_Facebook_Loader {
|
|
31 |
/**
|
32 |
* @var string the plugin version. This must be in the main plugin file to be automatically bumped by Woorelease.
|
33 |
*/
|
34 |
-
const PLUGIN_VERSION = '2.
|
35 |
|
36 |
// Minimum PHP version required by this plugin.
|
37 |
const MINIMUM_PHP_VERSION = '7.0.0';
|
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.6.0
|
14 |
* Text Domain: facebook-for-woocommerce
|
15 |
* WC requires at least: 3.5.0
|
16 |
+
* WC tested up to: 5.7.0
|
17 |
* Requires PHP: 7.0
|
18 |
*
|
19 |
* @package FacebookCommerce
|
31 |
/**
|
32 |
* @var string the plugin version. This must be in the main plugin file to be automatically bumped by Woorelease.
|
33 |
*/
|
34 |
+
const PLUGIN_VERSION = '2.6.0'; // WRCS: DEFINED_VERSION.
|
35 |
|
36 |
// Minimum PHP version required by this plugin.
|
37 |
const MINIMUM_PHP_VERSION = '7.0.0';
|
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.
|
6 |
"Report-Msgid-Bugs-To: "
|
7 |
"https://woocommerce.com/my-account/marketplace-ticket-form/\n"
|
8 |
-
"POT-Creation-Date: 2021-
|
9 |
"MIME-Version: 1.0\n"
|
10 |
"Content-Type: text/plain; charset=utf-8\n"
|
11 |
"Content-Transfer-Encoding: 8bit\n"
|
@@ -13,7 +13,7 @@ msgstr ""
|
|
13 |
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
14 |
"Language-Team: LANGUAGE <LL@li.org>\n"
|
15 |
|
16 |
-
#: class-wc-facebookcommerce.php:
|
17 |
#. translators: Placeholders %1$s - opening strong HTML tag, %2$s - closing
|
18 |
#. strong HTML tag, %3$s - opening link HTML tag, %4$s - closing link HTML tag
|
19 |
msgid ""
|
@@ -21,7 +21,7 @@ msgid ""
|
|
21 |
"Facebook for WooCommerce connection. Please %3$sclick here%4$s to reconnect!"
|
22 |
msgstr ""
|
23 |
|
24 |
-
#: class-wc-facebookcommerce.php:
|
25 |
#. translators: Placeholders %1$s - opening link HTML tag, %2$s - closing link
|
26 |
#. HTML tag
|
27 |
msgid ""
|
@@ -29,7 +29,7 @@ msgid ""
|
|
29 |
"under %1$sWooCommerce > Facebook%2$s."
|
30 |
msgstr ""
|
31 |
|
32 |
-
#: class-wc-facebookcommerce.php:
|
33 |
#. translators: Placeholders %1$s - opening strong HTML tag, %2$s - closing
|
34 |
#. strong HTML tag, %3$s - opening link HTML tag, %4$s - closing link HTML tag
|
35 |
msgid ""
|
@@ -37,7 +37,7 @@ msgid ""
|
|
37 |
"configuration, %3$scomplete the setup steps%4$s."
|
38 |
msgstr ""
|
39 |
|
40 |
-
#: class-wc-facebookcommerce.php:
|
41 |
#. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
|
42 |
#. <a> tag, %4$s - </a> tag
|
43 |
msgid ""
|
@@ -46,7 +46,7 @@ msgid ""
|
|
46 |
"Connection%4$s area."
|
47 |
msgstr ""
|
48 |
|
49 |
-
#: class-wc-facebookcommerce.php:
|
50 |
#. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
|
51 |
#. <a> tag, %4$s - </a> tag
|
52 |
msgid ""
|
@@ -55,51 +55,51 @@ msgid ""
|
|
55 |
"products."
|
56 |
msgstr ""
|
57 |
|
58 |
-
#: class-wc-facebookcommerce.php:
|
59 |
#. translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing
|
60 |
#. </a> HTML link tag
|
61 |
msgid "Heads up! The Facebook menu is now located under the %1$sMarketing%2$s menu."
|
62 |
msgstr ""
|
63 |
|
64 |
-
#: class-wc-facebookcommerce.php:
|
65 |
msgid "FB Product Sets"
|
66 |
msgstr ""
|
67 |
|
68 |
-
#: class-wc-facebookcommerce.php:
|
69 |
msgid "FB Product Set"
|
70 |
msgstr ""
|
71 |
|
72 |
-
#: class-wc-facebookcommerce.php:
|
73 |
#. translators: Edit item label
|
74 |
msgid "Edit %s"
|
75 |
msgstr ""
|
76 |
|
77 |
-
#: class-wc-facebookcommerce.php:
|
78 |
#. translators: Add new label
|
79 |
msgid "Add new %s"
|
80 |
msgstr ""
|
81 |
|
82 |
-
#: class-wc-facebookcommerce.php:
|
83 |
#. translators: No items found text
|
84 |
msgid "No %s found."
|
85 |
msgstr ""
|
86 |
|
87 |
-
#: class-wc-facebookcommerce.php:
|
88 |
#. translators: Search label
|
89 |
msgid "Search %s."
|
90 |
msgstr ""
|
91 |
|
92 |
-
#: class-wc-facebookcommerce.php:
|
93 |
#. translators: Text label
|
94 |
msgid "Separate %s with commas"
|
95 |
msgstr ""
|
96 |
|
97 |
-
#: class-wc-facebookcommerce.php:
|
98 |
#. translators: Text label
|
99 |
msgid "Choose from the most used %s"
|
100 |
msgstr ""
|
101 |
|
102 |
-
#: class-wc-facebookcommerce.php:
|
103 |
msgid "Cannot create the API instance because the access token is missing."
|
104 |
msgstr ""
|
105 |
|
@@ -107,69 +107,69 @@ msgstr ""
|
|
107 |
msgid "Facebook for WooCommerce"
|
108 |
msgstr ""
|
109 |
|
110 |
-
#: facebook-commerce.php:
|
111 |
msgid "Facebook Commerce and Dynamic Ads (Pixel) Extension"
|
112 |
msgstr ""
|
113 |
|
114 |
-
#: facebook-commerce.php:
|
115 |
msgid "Facebook ID:"
|
116 |
msgstr ""
|
117 |
|
118 |
-
#: facebook-commerce.php:
|
119 |
msgid "Variant IDs:"
|
120 |
msgstr ""
|
121 |
|
122 |
-
#: facebook-commerce.php:
|
123 |
msgid "Reset Facebook metadata"
|
124 |
msgstr ""
|
125 |
|
126 |
-
#: facebook-commerce.php:
|
127 |
msgid "Delete product(s) on Facebook"
|
128 |
msgstr ""
|
129 |
|
130 |
-
#: facebook-commerce.php:
|
131 |
msgid "This product is not yet synced to Facebook."
|
132 |
msgstr ""
|
133 |
|
134 |
-
#: facebook-commerce.php:
|
135 |
msgid "Nothing to update for product group for %1$s"
|
136 |
msgstr ""
|
137 |
|
138 |
-
#: facebook-commerce.php:
|
139 |
#. translators: Placeholders %1$s - original error message from Facebook API
|
140 |
msgid "There was an issue connecting to the Facebook API: %1$s"
|
141 |
msgstr ""
|
142 |
|
143 |
-
#: facebook-commerce.php:
|
144 |
msgid "Your connection has expired."
|
145 |
msgstr ""
|
146 |
|
147 |
-
#: facebook-commerce.php:
|
148 |
msgid ""
|
149 |
"Please click Manage connection > Advanced Options > Update Token to refresh "
|
150 |
"your connection to Facebook."
|
151 |
msgstr ""
|
152 |
|
153 |
-
#: facebook-commerce.php:
|
154 |
#. translators: Placeholders %s - error message
|
155 |
msgid "There was an error trying to sync the products to Facebook. %s"
|
156 |
msgstr ""
|
157 |
|
158 |
-
#: facebook-commerce.php:
|
159 |
msgid "Product sync is disabled."
|
160 |
msgstr ""
|
161 |
|
162 |
-
#: facebook-commerce.php:
|
163 |
msgid "The plugin is not configured or the Catalog ID is missing."
|
164 |
msgstr ""
|
165 |
|
166 |
-
#: facebook-commerce.php:
|
167 |
msgid ""
|
168 |
"A product sync is in progress. Please wait until the sync finishes before "
|
169 |
"starting a new one."
|
170 |
msgstr ""
|
171 |
|
172 |
-
#: facebook-commerce.php:
|
173 |
msgid ""
|
174 |
"We've detected that your Facebook Product Catalog is no longer valid. This "
|
175 |
"may happen if it was deleted, but could also be a temporary error. If the "
|
@@ -177,33 +177,33 @@ msgid ""
|
|
177 |
"and setup the plugin again."
|
178 |
msgstr ""
|
179 |
|
180 |
-
#: facebook-commerce.php:
|
181 |
msgid "We couldn't create the feed or upload the product information."
|
182 |
msgstr ""
|
183 |
|
184 |
-
#: facebook-commerce.php:
|
185 |
msgid "Hi! We're here to answer any questions you may have."
|
186 |
msgstr ""
|
187 |
|
188 |
-
#: facebook-commerce.php:
|
189 |
msgid "Facebook for WooCommerce error:"
|
190 |
msgstr ""
|
191 |
|
192 |
-
#: facebook-commerce.php:
|
193 |
msgid ""
|
194 |
"There was an error trying to retrieve information about the Facebook page: "
|
195 |
"%s"
|
196 |
msgstr ""
|
197 |
|
198 |
-
#: facebook-commerce.php:
|
199 |
msgid "Get started with Messenger Customer Chat"
|
200 |
msgstr ""
|
201 |
|
202 |
-
#: facebook-commerce.php:
|
203 |
msgid "Get started with Instagram Shopping"
|
204 |
msgstr ""
|
205 |
|
206 |
-
#: facebook-commerce.php:
|
207 |
#. translators: Placeholders %1$s - original error message from Facebook API
|
208 |
msgid "There was an issue connecting to the Facebook API: %s"
|
209 |
msgstr ""
|
@@ -240,11 +240,11 @@ msgstr ""
|
|
240 |
msgid "Order not found"
|
241 |
msgstr ""
|
242 |
|
243 |
-
#: includes/AJAX.php:337 includes/AJAX.php:
|
244 |
msgid "Go to Settings"
|
245 |
msgstr ""
|
246 |
|
247 |
-
#: includes/AJAX.php:342 includes/AJAX.php:
|
248 |
#: includes/Admin/Product_Categories.php:118
|
249 |
#: includes/Admin/Settings_Screens/Product_Sync.php:157 includes/Admin.php:391
|
250 |
msgid "Cancel"
|
@@ -259,7 +259,7 @@ msgid ""
|
|
259 |
"or click Cancel and update the product's category / tag assignments."
|
260 |
msgstr ""
|
261 |
|
262 |
-
#: includes/AJAX.php:
|
263 |
msgid ""
|
264 |
"One or more of the selected products belongs to a category or tag that is "
|
265 |
"excluded from the Facebook catalog sync. To sync these products to "
|
@@ -267,11 +267,11 @@ msgid ""
|
|
267 |
"settings."
|
268 |
msgstr ""
|
269 |
|
270 |
-
#: includes/AJAX.php:
|
271 |
msgid "Exclude Products"
|
272 |
msgstr ""
|
273 |
|
274 |
-
#: includes/AJAX.php:
|
275 |
#. translators: Placeholder %s - <br/> tags
|
276 |
msgid ""
|
277 |
"The categories and/or tags that you have selected to exclude from sync "
|
@@ -980,10 +980,42 @@ msgstr ""
|
|
980 |
msgid "Page %s not authorized."
|
981 |
msgstr ""
|
982 |
|
983 |
-
#: includes/Handlers/Connection.php:
|
984 |
msgid "You do not have permission to finish App Store login."
|
985 |
msgstr ""
|
986 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
987 |
#: includes/Products/Sync/Background.php:68
|
988 |
msgid "Job data key \"%s\" not set"
|
989 |
msgstr ""
|
@@ -1014,19 +1046,19 @@ msgstr ""
|
|
1014 |
msgid "Dismiss"
|
1015 |
msgstr ""
|
1016 |
|
1017 |
-
#: includes/fbproductfeed.php:
|
1018 |
msgid "Could not create product catalog feed directory"
|
1019 |
msgstr ""
|
1020 |
|
1021 |
-
#: includes/fbproductfeed.php:
|
1022 |
msgid "Could not open the product catalog temporary feed file for writing"
|
1023 |
msgstr ""
|
1024 |
|
1025 |
-
#: includes/fbproductfeed.php:
|
1026 |
msgid "Could not open the product catalog feed file for writing"
|
1027 |
msgstr ""
|
1028 |
|
1029 |
-
#: includes/fbproductfeed.php:
|
1030 |
msgid "Could not rename the product catalog feed file"
|
1031 |
msgstr ""
|
1032 |
|
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.6.0\n"
|
6 |
"Report-Msgid-Bugs-To: "
|
7 |
"https://woocommerce.com/my-account/marketplace-ticket-form/\n"
|
8 |
+
"POT-Creation-Date: 2021-06-10 18:28:50+00:00\n"
|
9 |
"MIME-Version: 1.0\n"
|
10 |
"Content-Type: text/plain; charset=utf-8\n"
|
11 |
"Content-Transfer-Encoding: 8bit\n"
|
13 |
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
14 |
"Language-Team: LANGUAGE <LL@li.org>\n"
|
15 |
|
16 |
+
#: class-wc-facebookcommerce.php:261
|
17 |
#. translators: Placeholders %1$s - opening strong HTML tag, %2$s - closing
|
18 |
#. strong HTML tag, %3$s - opening link HTML tag, %4$s - closing link HTML tag
|
19 |
msgid ""
|
21 |
"Facebook for WooCommerce connection. Please %3$sclick here%4$s to reconnect!"
|
22 |
msgstr ""
|
23 |
|
24 |
+
#: class-wc-facebookcommerce.php:282
|
25 |
#. translators: Placeholders %1$s - opening link HTML tag, %2$s - closing link
|
26 |
#. HTML tag
|
27 |
msgid ""
|
29 |
"under %1$sWooCommerce > Facebook%2$s."
|
30 |
msgstr ""
|
31 |
|
32 |
+
#: class-wc-facebookcommerce.php:302
|
33 |
#. translators: Placeholders %1$s - opening strong HTML tag, %2$s - closing
|
34 |
#. strong HTML tag, %3$s - opening link HTML tag, %4$s - closing link HTML tag
|
35 |
msgid ""
|
37 |
"configuration, %3$scomplete the setup steps%4$s."
|
38 |
msgstr ""
|
39 |
|
40 |
+
#: class-wc-facebookcommerce.php:334
|
41 |
#. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
|
42 |
#. <a> tag, %4$s - </a> tag
|
43 |
msgid ""
|
46 |
"Connection%4$s area."
|
47 |
msgstr ""
|
48 |
|
49 |
+
#: class-wc-facebookcommerce.php:357
|
50 |
#. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
|
51 |
#. <a> tag, %4$s - </a> tag
|
52 |
msgid ""
|
55 |
"products."
|
56 |
msgstr ""
|
57 |
|
58 |
+
#: class-wc-facebookcommerce.php:383
|
59 |
#. translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing
|
60 |
#. </a> HTML link tag
|
61 |
msgid "Heads up! The Facebook menu is now located under the %1$sMarketing%2$s menu."
|
62 |
msgstr ""
|
63 |
|
64 |
+
#: class-wc-facebookcommerce.php:455
|
65 |
msgid "FB Product Sets"
|
66 |
msgstr ""
|
67 |
|
68 |
+
#: class-wc-facebookcommerce.php:456
|
69 |
msgid "FB Product Set"
|
70 |
msgstr ""
|
71 |
|
72 |
+
#: class-wc-facebookcommerce.php:464
|
73 |
#. translators: Edit item label
|
74 |
msgid "Edit %s"
|
75 |
msgstr ""
|
76 |
|
77 |
+
#: class-wc-facebookcommerce.php:466
|
78 |
#. translators: Add new label
|
79 |
msgid "Add new %s"
|
80 |
msgstr ""
|
81 |
|
82 |
+
#: class-wc-facebookcommerce.php:469
|
83 |
#. translators: No items found text
|
84 |
msgid "No %s found."
|
85 |
msgstr ""
|
86 |
|
87 |
+
#: class-wc-facebookcommerce.php:471
|
88 |
#. translators: Search label
|
89 |
msgid "Search %s."
|
90 |
msgstr ""
|
91 |
|
92 |
+
#: class-wc-facebookcommerce.php:473
|
93 |
#. translators: Text label
|
94 |
msgid "Separate %s with commas"
|
95 |
msgstr ""
|
96 |
|
97 |
+
#: class-wc-facebookcommerce.php:475
|
98 |
#. translators: Text label
|
99 |
msgid "Choose from the most used %s"
|
100 |
msgstr ""
|
101 |
|
102 |
+
#: class-wc-facebookcommerce.php:591
|
103 |
msgid "Cannot create the API instance because the access token is missing."
|
104 |
msgstr ""
|
105 |
|
107 |
msgid "Facebook for WooCommerce"
|
108 |
msgstr ""
|
109 |
|
110 |
+
#: facebook-commerce.php:230
|
111 |
msgid "Facebook Commerce and Dynamic Ads (Pixel) Extension"
|
112 |
msgstr ""
|
113 |
|
114 |
+
#: facebook-commerce.php:642
|
115 |
msgid "Facebook ID:"
|
116 |
msgstr ""
|
117 |
|
118 |
+
#: facebook-commerce.php:650
|
119 |
msgid "Variant IDs:"
|
120 |
msgstr ""
|
121 |
|
122 |
+
#: facebook-commerce.php:668
|
123 |
msgid "Reset Facebook metadata"
|
124 |
msgstr ""
|
125 |
|
126 |
+
#: facebook-commerce.php:673
|
127 |
msgid "Delete product(s) on Facebook"
|
128 |
msgstr ""
|
129 |
|
130 |
+
#: facebook-commerce.php:681
|
131 |
msgid "This product is not yet synced to Facebook."
|
132 |
msgstr ""
|
133 |
|
134 |
+
#: facebook-commerce.php:1493
|
135 |
msgid "Nothing to update for product group for %1$s"
|
136 |
msgstr ""
|
137 |
|
138 |
+
#: facebook-commerce.php:1887
|
139 |
#. translators: Placeholders %1$s - original error message from Facebook API
|
140 |
msgid "There was an issue connecting to the Facebook API: %1$s"
|
141 |
msgstr ""
|
142 |
|
143 |
+
#: facebook-commerce.php:2223
|
144 |
msgid "Your connection has expired."
|
145 |
msgstr ""
|
146 |
|
147 |
+
#: facebook-commerce.php:2223
|
148 |
msgid ""
|
149 |
"Please click Manage connection > Advanced Options > Update Token to refresh "
|
150 |
"your connection to Facebook."
|
151 |
msgstr ""
|
152 |
|
153 |
+
#: facebook-commerce.php:2230
|
154 |
#. translators: Placeholders %s - error message
|
155 |
msgid "There was an error trying to sync the products to Facebook. %s"
|
156 |
msgstr ""
|
157 |
|
158 |
+
#: facebook-commerce.php:2253 facebook-commerce.php:2426
|
159 |
msgid "Product sync is disabled."
|
160 |
msgstr ""
|
161 |
|
162 |
+
#: facebook-commerce.php:2260 facebook-commerce.php:2433
|
163 |
msgid "The plugin is not configured or the Catalog ID is missing."
|
164 |
msgstr ""
|
165 |
|
166 |
+
#: facebook-commerce.php:2283
|
167 |
msgid ""
|
168 |
"A product sync is in progress. Please wait until the sync finishes before "
|
169 |
"starting a new one."
|
170 |
msgstr ""
|
171 |
|
172 |
+
#: facebook-commerce.php:2295 facebook-commerce.php:2447
|
173 |
msgid ""
|
174 |
"We've detected that your Facebook Product Catalog is no longer valid. This "
|
175 |
"may happen if it was deleted, but could also be a temporary error. If the "
|
177 |
"and setup the plugin again."
|
178 |
msgstr ""
|
179 |
|
180 |
+
#: facebook-commerce.php:2471
|
181 |
msgid "We couldn't create the feed or upload the product information."
|
182 |
msgstr ""
|
183 |
|
184 |
+
#: facebook-commerce.php:2939
|
185 |
msgid "Hi! We're here to answer any questions you may have."
|
186 |
msgstr ""
|
187 |
|
188 |
+
#: facebook-commerce.php:3306
|
189 |
msgid "Facebook for WooCommerce error:"
|
190 |
msgstr ""
|
191 |
|
192 |
+
#: facebook-commerce.php:3388
|
193 |
msgid ""
|
194 |
"There was an error trying to retrieve information about the Facebook page: "
|
195 |
"%s"
|
196 |
msgstr ""
|
197 |
|
198 |
+
#: facebook-commerce.php:3439
|
199 |
msgid "Get started with Messenger Customer Chat"
|
200 |
msgstr ""
|
201 |
|
202 |
+
#: facebook-commerce.php:3440
|
203 |
msgid "Get started with Instagram Shopping"
|
204 |
msgstr ""
|
205 |
|
206 |
+
#: facebook-commerce.php:3675
|
207 |
#. translators: Placeholders %1$s - original error message from Facebook API
|
208 |
msgid "There was an issue connecting to the Facebook API: %s"
|
209 |
msgstr ""
|
240 |
msgid "Order not found"
|
241 |
msgstr ""
|
242 |
|
243 |
+
#: includes/AJAX.php:337 includes/AJAX.php:405
|
244 |
msgid "Go to Settings"
|
245 |
msgstr ""
|
246 |
|
247 |
+
#: includes/AJAX.php:342 includes/AJAX.php:410 includes/AJAX.php:476
|
248 |
#: includes/Admin/Product_Categories.php:118
|
249 |
#: includes/Admin/Settings_Screens/Product_Sync.php:157 includes/Admin.php:391
|
250 |
msgid "Cancel"
|
259 |
"or click Cancel and update the product's category / tag assignments."
|
260 |
msgstr ""
|
261 |
|
262 |
+
#: includes/AJAX.php:417
|
263 |
msgid ""
|
264 |
"One or more of the selected products belongs to a category or tag that is "
|
265 |
"excluded from the Facebook catalog sync. To sync these products to "
|
267 |
"settings."
|
268 |
msgstr ""
|
269 |
|
270 |
+
#: includes/AJAX.php:470
|
271 |
msgid "Exclude Products"
|
272 |
msgstr ""
|
273 |
|
274 |
+
#: includes/AJAX.php:485
|
275 |
#. translators: Placeholder %s - <br/> tags
|
276 |
msgid ""
|
277 |
"The categories and/or tags that you have selected to exclude from sync "
|
980 |
msgid "Page %s not authorized."
|
981 |
msgstr ""
|
982 |
|
983 |
+
#: includes/Handlers/Connection.php:1379
|
984 |
msgid "You do not have permission to finish App Store login."
|
985 |
msgstr ""
|
986 |
|
987 |
+
#: includes/ProductSync/ProductValidator.php:148
|
988 |
+
msgid "Product sync is globally disabled."
|
989 |
+
msgstr ""
|
990 |
+
|
991 |
+
#: includes/ProductSync/ProductValidator.php:161
|
992 |
+
msgid "Product is not published."
|
993 |
+
msgstr ""
|
994 |
+
|
995 |
+
#: includes/ProductSync/ProductValidator.php:172
|
996 |
+
msgid "Product must be in stock."
|
997 |
+
msgstr ""
|
998 |
+
|
999 |
+
#: includes/ProductSync/ProductValidator.php:187
|
1000 |
+
msgid "Product is hidden from catalog and search."
|
1001 |
+
msgstr ""
|
1002 |
+
|
1003 |
+
#: includes/ProductSync/ProductValidator.php:202
|
1004 |
+
msgid "Product excluded because of categories."
|
1005 |
+
msgstr ""
|
1006 |
+
|
1007 |
+
#: includes/ProductSync/ProductValidator.php:209
|
1008 |
+
msgid "Product excluded because of tags."
|
1009 |
+
msgstr ""
|
1010 |
+
|
1011 |
+
#: includes/ProductSync/ProductValidator.php:220
|
1012 |
+
msgid "Sync disabled in product field."
|
1013 |
+
msgstr ""
|
1014 |
+
|
1015 |
+
#: includes/ProductSync/ProductValidator.php:255
|
1016 |
+
msgid "If product is not simple, variable or variation it must have a price."
|
1017 |
+
msgstr ""
|
1018 |
+
|
1019 |
#: includes/Products/Sync/Background.php:68
|
1020 |
msgid "Job data key \"%s\" not set"
|
1021 |
msgstr ""
|
1046 |
msgid "Dismiss"
|
1047 |
msgstr ""
|
1048 |
|
1049 |
+
#: includes/fbproductfeed.php:469
|
1050 |
msgid "Could not create product catalog feed directory"
|
1051 |
msgstr ""
|
1052 |
|
1053 |
+
#: includes/fbproductfeed.php:534
|
1054 |
msgid "Could not open the product catalog temporary feed file for writing"
|
1055 |
msgstr ""
|
1056 |
|
1057 |
+
#: includes/fbproductfeed.php:541
|
1058 |
msgid "Could not open the product catalog feed file for writing"
|
1059 |
msgstr ""
|
1060 |
|
1061 |
+
#: includes/fbproductfeed.php:584
|
1062 |
msgid "Could not rename the product catalog feed file"
|
1063 |
msgstr ""
|
1064 |
|
includes/AJAX.php
CHANGED
@@ -384,12 +384,9 @@ class AJAX {
|
|
384 |
$has_excluded_term = false;
|
385 |
|
386 |
foreach ( $product_ids as $product_id ) {
|
387 |
-
|
388 |
$product = wc_get_product( $product_id );
|
389 |
|
390 |
-
|
391 |
-
if ( $product instanceof \WC_Product && Products::is_sync_excluded_for_product_terms( $product ) ) {
|
392 |
-
|
393 |
$has_excluded_term = true;
|
394 |
break;
|
395 |
}
|
384 |
$has_excluded_term = false;
|
385 |
|
386 |
foreach ( $product_ids as $product_id ) {
|
|
|
387 |
$product = wc_get_product( $product_id );
|
388 |
|
389 |
+
if ( $product instanceof \WC_Product && ! facebook_for_woocommerce()->get_product_sync_validator( $product )->passes_product_terms_check() ) {
|
|
|
|
|
390 |
$has_excluded_term = true;
|
391 |
break;
|
392 |
}
|
includes/API/FBE/Configuration/Read/Response.php
CHANGED
@@ -40,5 +40,40 @@ class Response extends API\Response {
|
|
40 |
return $configuration;
|
41 |
}
|
42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
|
44 |
}
|
40 |
return $configuration;
|
41 |
}
|
42 |
|
43 |
+
/**
|
44 |
+
* Is Instagram Shopping enabled?
|
45 |
+
*
|
46 |
+
* @since 2.6.0
|
47 |
+
*
|
48 |
+
* @return boolean
|
49 |
+
*/
|
50 |
+
public function is_ig_shopping_enabled() {
|
51 |
+
|
52 |
+
$ig_shopping_enabled = false;
|
53 |
+
|
54 |
+
if ( ! empty( $this->response_data->ig_shopping ) && is_object( $this->response_data->ig_shopping ) ) {
|
55 |
+
$ig_shopping_enabled = ! ! $this->response_data->ig_shopping->enabled;
|
56 |
+
}
|
57 |
+
|
58 |
+
return $ig_shopping_enabled;
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Is Instagram CTA enabled?
|
63 |
+
*
|
64 |
+
* @since 2.6.0
|
65 |
+
*
|
66 |
+
* @return boolean
|
67 |
+
*/
|
68 |
+
public function is_ig_cta_enabled() {
|
69 |
+
|
70 |
+
$ig_cta_enabled = false;
|
71 |
+
|
72 |
+
if ( ! empty( $this->response_data->ig_cta ) && is_object( $this->response_data->ig_cta ) ) {
|
73 |
+
$ig_cta_enabled = ! ! $this->response_data->ig_cta->enabled;
|
74 |
+
}
|
75 |
+
|
76 |
+
return $ig_cta_enabled;
|
77 |
+
}
|
78 |
|
79 |
}
|
includes/Feed/FeedConfigurationDetection.php
ADDED
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace SkyVerge\WooCommerce\Facebook\Feed;
|
4 |
+
|
5 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
6 |
+
exit;
|
7 |
+
}
|
8 |
+
|
9 |
+
use Error;
|
10 |
+
use SkyVerge\WooCommerce\Facebook\Utilities\Heartbeat;
|
11 |
+
use SkyVerge\WooCommerce\Facebook\Products\Feed;
|
12 |
+
|
13 |
+
/**
|
14 |
+
* A class responsible detecting feed configuration.
|
15 |
+
*/
|
16 |
+
class FeedConfigurationDetection {
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Constructor.
|
20 |
+
*/
|
21 |
+
public function __construct() {
|
22 |
+
add_action( Heartbeat::DAILY, array( $this, 'track_data_source_feed_tracker_info' ) );
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Store config settings for feed-based sync for WooCommerce Tracker.
|
27 |
+
*
|
28 |
+
* Gets various settings related to the feed, and data about recent uploads.
|
29 |
+
* This is formatted into an array of keys/values, and saved to a transient for inclusion in tracker snapshot.
|
30 |
+
* Note this does not send the data to tracker - this happens later (see Tracker class).
|
31 |
+
*
|
32 |
+
* @since 2.6.0
|
33 |
+
* @return void
|
34 |
+
*/
|
35 |
+
public function track_data_source_feed_tracker_info() {
|
36 |
+
try {
|
37 |
+
$info = $this->get_data_source_feed_tracker_info();
|
38 |
+
facebook_for_woocommerce()->get_tracker()->track_facebook_feed_config( $info );
|
39 |
+
} catch ( \Error $error ) {
|
40 |
+
facebook_for_woocommerce()->log( 'Unable to detect valid feed configuration: ' . $error->getMessage() );
|
41 |
+
}
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Get config settings for feed-based sync for WooCommerce Tracker.
|
46 |
+
*
|
47 |
+
* @throws Error Catalog id missing.
|
48 |
+
* @return Array Key-value array of various configuration settings.
|
49 |
+
*/
|
50 |
+
private function get_data_source_feed_tracker_info() {
|
51 |
+
$integration = facebook_for_woocommerce()->get_integration();
|
52 |
+
$graph_api = $integration->get_graph_api();
|
53 |
+
$integration_feed_id = $integration->get_feed_id();
|
54 |
+
$catalog_id = $integration->get_product_catalog_id();
|
55 |
+
|
56 |
+
$info = array();
|
57 |
+
$info['site-feed-id'] = $integration_feed_id;
|
58 |
+
|
59 |
+
// No catalog id. Most probably means that we don't have a valid connection.
|
60 |
+
if ( '' === $catalog_id ) {
|
61 |
+
throw new Error( 'No catalog ID' );
|
62 |
+
}
|
63 |
+
|
64 |
+
// Get all feeds configured for the catalog.
|
65 |
+
$feed_nodes = $this->get_feed_nodes_for_catalog( $catalog_id, $graph_api );
|
66 |
+
|
67 |
+
$info['feed-count'] = count( $feed_nodes );
|
68 |
+
|
69 |
+
// Check if the catalog has any feed configured.
|
70 |
+
if ( empty( $feed_nodes ) ) {
|
71 |
+
throw new Error( 'No feed nodes for catalog' );
|
72 |
+
}
|
73 |
+
|
74 |
+
/*
|
75 |
+
* We will only track settings for one feed config (for now at least).
|
76 |
+
* So we need to determine which is the most relevant feed.
|
77 |
+
* If there is only one, we use that.
|
78 |
+
* If one has the same ID as $integration_feed_id, we use that.
|
79 |
+
* Otherwise we pick the one that was most recently updated.
|
80 |
+
*/
|
81 |
+
$active_feed_metadata = null;
|
82 |
+
foreach ( $feed_nodes as $feed ) {
|
83 |
+
$metadata = $this->get_feed_metadata( $feed['id'], $graph_api );
|
84 |
+
|
85 |
+
if ( $feed['id'] === $integration_feed_id ) {
|
86 |
+
$active_feed_metadata = $metadata;
|
87 |
+
break;
|
88 |
+
}
|
89 |
+
|
90 |
+
if ( ! array_key_exists( 'latest_upload', $metadata ) || ! array_key_exists( 'start_time', $metadata['latest_upload'] ) ) {
|
91 |
+
continue;
|
92 |
+
}
|
93 |
+
$metadata['latest_upload_time'] = strtotime( $metadata['latest_upload']['start_time'] );
|
94 |
+
if ( ! $active_feed_metadata ||
|
95 |
+
( $metadata['latest_upload_time'] > $active_feed_metadata['latest_upload_time'] ) ) {
|
96 |
+
$active_feed_metadata = $metadata;
|
97 |
+
}
|
98 |
+
}
|
99 |
+
|
100 |
+
$active_feed['created-time'] = gmdate( 'Y-m-d H:i:s', strtotime( $active_feed_metadata['created_time'] ) );
|
101 |
+
$active_feed['product-count'] = $active_feed_metadata['product_count'];
|
102 |
+
|
103 |
+
/*
|
104 |
+
* Upload schedule settings can be in two keys:
|
105 |
+
* `schedule` => full replace of catalog with items in feed (including delete).
|
106 |
+
* `update_schedule` => append any new or updated products to catalog.
|
107 |
+
* These may both be configured; we will track settings for each individually (i.e. both).
|
108 |
+
* https://developers.facebook.com/docs/marketing-api/reference/product-feed/
|
109 |
+
*/
|
110 |
+
if ( array_key_exists( 'schedule', $active_feed_metadata ) ) {
|
111 |
+
$active_feed['schedule']['interval'] = $active_feed_metadata['schedule']['interval'];
|
112 |
+
$active_feed['schedule']['interval-count'] = $active_feed_metadata['schedule']['interval_count'];
|
113 |
+
}
|
114 |
+
if ( array_key_exists( 'update_schedule', $active_feed_metadata ) ) {
|
115 |
+
$active_feed['update-schedule']['interval'] = $active_feed_metadata['update_schedule']['interval'];
|
116 |
+
$active_feed['update-schedule']['interval-count'] = $active_feed_metadata['update_schedule']['interval_count'];
|
117 |
+
}
|
118 |
+
|
119 |
+
$info['active-feed'] = $active_feed;
|
120 |
+
|
121 |
+
$latest_upload = $active_feed_metadata['latest_upload'];
|
122 |
+
if ( array_key_exists( 'latest_upload', $active_feed_metadata ) ) {
|
123 |
+
$upload = array();
|
124 |
+
|
125 |
+
if ( array_key_exists( 'end_time', $latest_upload ) ) {
|
126 |
+
$upload['end-time'] = gmdate( 'Y-m-d H:i:s', strtotime( $latest_upload['end_time'] ) );
|
127 |
+
}
|
128 |
+
|
129 |
+
// Get more detailed metadata about the most recent feed upload.
|
130 |
+
$upload_metadata = $this->get_feed_upload_metadata( $latest_upload['id'], $graph_api );
|
131 |
+
|
132 |
+
$upload['error-count'] = $upload_metadata['error_count'];
|
133 |
+
$upload['warning-count'] = $upload_metadata['warning_count'];
|
134 |
+
$upload['num-detected-items'] = $upload_metadata['num_detected_items'];
|
135 |
+
$upload['num-persisted-items'] = $upload_metadata['num_persisted_items'];
|
136 |
+
|
137 |
+
// True if the feed upload url (Facebook side) matches the feed endpoint URL and secret.
|
138 |
+
// If it doesn't match, it's likely it's unused.
|
139 |
+
$upload['url-matches-site-endpoint'] = wc_bool_to_string(
|
140 |
+
Feed::get_feed_data_url() === $upload_metadata['url']
|
141 |
+
);
|
142 |
+
|
143 |
+
$info['active-feed']['latest-upload'] = $upload;
|
144 |
+
}
|
145 |
+
|
146 |
+
return $info;
|
147 |
+
}
|
148 |
+
|
149 |
+
/**
|
150 |
+
* Given catalog id this function fetches all feed configurations defined for this catalog.
|
151 |
+
*
|
152 |
+
* @throws Error Feed configurations fetch was not successful.
|
153 |
+
* @param String $catalog_id Facebook Catalog ID.
|
154 |
+
* @param WC_Facebookcommerce_Graph_API $graph_api Facebook Graph handler instance.
|
155 |
+
*
|
156 |
+
* @return Array Array of feed configurations.
|
157 |
+
*/
|
158 |
+
private function get_feed_nodes_for_catalog( $catalog_id, $graph_api ) {
|
159 |
+
// Read all the feed configurations specified for the catalog.
|
160 |
+
$response = $graph_api->read_feeds( $catalog_id );
|
161 |
+
$code = (int) wp_remote_retrieve_response_code( $response );
|
162 |
+
if ( 200 !== $code ) {
|
163 |
+
throw new Error( 'Reading catalog feeds error', $code );
|
164 |
+
}
|
165 |
+
|
166 |
+
$response_body = wp_remote_retrieve_body( $response );
|
167 |
+
|
168 |
+
$body = json_decode( $response_body, true );
|
169 |
+
return $body['data'];
|
170 |
+
}
|
171 |
+
|
172 |
+
/**
|
173 |
+
* Given feed id fetch this feed configuration metadata.
|
174 |
+
*
|
175 |
+
* @throws Error Feed metadata fetch was not successful.
|
176 |
+
* @param String $feed_id Facebook Feed ID.
|
177 |
+
* @param WC_Facebookcommerce_Graph_API $graph_api Facebook Graph handler instance.
|
178 |
+
*
|
179 |
+
* @return Array Array of feed configurations.
|
180 |
+
*/
|
181 |
+
private function get_feed_metadata( $feed_id, $graph_api ) {
|
182 |
+
$response = $graph_api->read_feed_metadata( $feed_id );
|
183 |
+
$code = (int) wp_remote_retrieve_response_code( $response );
|
184 |
+
if ( 200 !== $code ) {
|
185 |
+
throw new Error( 'Error reading feed metadata', $code );
|
186 |
+
}
|
187 |
+
$response_body = wp_remote_retrieve_body( $response );
|
188 |
+
return json_decode( $response_body, true );
|
189 |
+
}
|
190 |
+
|
191 |
+
/**
|
192 |
+
* Given upload id fetch this upload execution metadata.
|
193 |
+
*
|
194 |
+
* @throws Error Upload metadata fetch was not successful.
|
195 |
+
* @param String $upload_id Facebook Feed upload ID.
|
196 |
+
* @param WC_Facebookcommerce_Graph_API $graph_api Facebook Graph handler instance.
|
197 |
+
*
|
198 |
+
* @return Array Array of feed configurations.
|
199 |
+
*/
|
200 |
+
private function get_feed_upload_metadata( $upload_id, $graph_api ) {
|
201 |
+
$response = $graph_api->read_upload_metadata( $upload_id );
|
202 |
+
$code = (int) wp_remote_retrieve_response_code( $response );
|
203 |
+
if ( 200 !== $code ) {
|
204 |
+
throw new Error( 'Error reading feed upload metadata', $code );
|
205 |
+
}
|
206 |
+
$response_body = wp_remote_retrieve_body( $response );
|
207 |
+
return json_decode( $response_body, true );
|
208 |
+
}
|
209 |
+
|
210 |
+
}
|
includes/Handlers/Connection.php
CHANGED
@@ -143,6 +143,10 @@ class Connection {
|
|
143 |
try {
|
144 |
|
145 |
$response = $this->get_plugin()->get_api()->get_business_configuration( $this->get_external_business_id() );
|
|
|
|
|
|
|
|
|
146 |
|
147 |
// update the messenger settings
|
148 |
if ( $messenger_configuration = $response->get_messenger_configuration() ) {
|
@@ -163,10 +167,8 @@ class Connection {
|
|
163 |
}
|
164 |
}
|
165 |
} catch ( SV_WC_API_Exception $exception ) {
|
166 |
-
|
167 |
-
|
168 |
-
$this->get_plugin()->log( 'Could not refresh business configuration. ' . $exception->getMessage() );
|
169 |
-
}
|
170 |
}
|
171 |
|
172 |
set_transient( 'wc_facebook_business_configuration_refresh', time(), HOUR_IN_SECONDS );
|
@@ -196,9 +198,7 @@ class Connection {
|
|
196 |
|
197 |
} catch ( SV_WC_API_Exception $exception ) {
|
198 |
|
199 |
-
|
200 |
-
$this->get_plugin()->log( 'Could not refresh installation data. ' . $exception->getMessage() );
|
201 |
-
}
|
202 |
}
|
203 |
|
204 |
set_transient( 'wc_facebook_connection_refresh', time(), DAY_IN_SECONDS );
|
@@ -1185,19 +1185,17 @@ class Connection {
|
|
1185 |
// Reject other objects other than subscribed object
|
1186 |
if ( empty( $data ) || ! isset( $data->object ) || self::WEBHOOK_SUBSCRIBED_OBJECT !== $data->object ) {
|
1187 |
|
1188 |
-
|
1189 |
-
|
1190 |
-
|
1191 |
-
}
|
1192 |
-
|
1193 |
return;
|
1194 |
}
|
1195 |
|
1196 |
$log_data = array();
|
1197 |
-
|
1198 |
-
|
1199 |
-
|
1200 |
-
|
1201 |
|
1202 |
$entry = (array) $data->entry[0];
|
1203 |
if ( empty( $entry ) ) {
|
@@ -1309,16 +1307,12 @@ class Connection {
|
|
1309 |
|
1310 |
} catch ( \Exception $e ) {
|
1311 |
|
1312 |
-
|
1313 |
-
$this->get_plugin()->log( 'Could not request Page Token: ' . $e->getMessage() );
|
1314 |
-
}
|
1315 |
}
|
1316 |
}//end if
|
1317 |
|
1318 |
-
|
1319 |
-
|
1320 |
-
$this->get_plugin()->log( print_r( $log_data, true ) ); //phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
|
1321 |
-
}
|
1322 |
}
|
1323 |
|
1324 |
|
143 |
try {
|
144 |
|
145 |
$response = $this->get_plugin()->get_api()->get_business_configuration( $this->get_external_business_id() );
|
146 |
+
facebook_for_woocommerce()->get_tracker()->track_facebook_business_config(
|
147 |
+
$response->is_ig_shopping_enabled(),
|
148 |
+
$response->is_ig_cta_enabled()
|
149 |
+
);
|
150 |
|
151 |
// update the messenger settings
|
152 |
if ( $messenger_configuration = $response->get_messenger_configuration() ) {
|
167 |
}
|
168 |
}
|
169 |
} catch ( SV_WC_API_Exception $exception ) {
|
170 |
+
|
171 |
+
$this->get_plugin()->log( 'Could not refresh business configuration. ' . $exception->getMessage() );
|
|
|
|
|
172 |
}
|
173 |
|
174 |
set_transient( 'wc_facebook_business_configuration_refresh', time(), HOUR_IN_SECONDS );
|
198 |
|
199 |
} catch ( SV_WC_API_Exception $exception ) {
|
200 |
|
201 |
+
$this->get_plugin()->log( 'Could not refresh installation data. ' . $exception->getMessage() );
|
|
|
|
|
202 |
}
|
203 |
|
204 |
set_transient( 'wc_facebook_connection_refresh', time(), DAY_IN_SECONDS );
|
1185 |
// Reject other objects other than subscribed object
|
1186 |
if ( empty( $data ) || ! isset( $data->object ) || self::WEBHOOK_SUBSCRIBED_OBJECT !== $data->object ) {
|
1187 |
|
1188 |
+
$this->get_plugin()->log( 'Wrong (or empty) WebHook Event received' );
|
1189 |
+
$this->get_plugin()->log( print_r( $data, true ) ); //phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
|
1190 |
+
|
|
|
|
|
1191 |
return;
|
1192 |
}
|
1193 |
|
1194 |
$log_data = array();
|
1195 |
+
|
1196 |
+
$this->get_plugin()->log( 'WebHook User Event received' );
|
1197 |
+
$this->get_plugin()->log( print_r( $data, true ) ); //phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
|
1198 |
+
|
1199 |
|
1200 |
$entry = (array) $data->entry[0];
|
1201 |
if ( empty( $entry ) ) {
|
1307 |
|
1308 |
} catch ( \Exception $e ) {
|
1309 |
|
1310 |
+
$this->get_plugin()->log( 'Could not request Page Token: ' . $e->getMessage() );
|
|
|
|
|
1311 |
}
|
1312 |
}//end if
|
1313 |
|
1314 |
+
$this->get_plugin()->log( 'WebHook User event saved data' );
|
1315 |
+
$this->get_plugin()->log( print_r( $log_data, true ) ); //phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
|
|
|
|
|
1316 |
}
|
1317 |
|
1318 |
|
includes/Jobs/CleanupSkyvergeFrameworkJobOptions.php
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace SkyVerge\WooCommerce\Facebook\Jobs;
|
4 |
+
|
5 |
+
use SkyVerge\WooCommerce\Facebook\Utilities\Heartbeat;
|
6 |
+
|
7 |
+
defined( 'ABSPATH' ) || exit;
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Class CleanupSkyvergeFrameworkJobOptions
|
11 |
+
*
|
12 |
+
* Responsible for cleaning up old completed background sync jobs from SkyVerge background job system.
|
13 |
+
* Each job is represented by a row in wp_options table, and these can accumulate over time.
|
14 |
+
*
|
15 |
+
* Note - this is closely coupled to the SkyVerge background job system, and is essentially a patch to improve it.
|
16 |
+
*
|
17 |
+
* @see SV_WP_Background_Job_Handler
|
18 |
+
*
|
19 |
+
* @since 2.6.0
|
20 |
+
*/
|
21 |
+
class CleanupSkyvergeFrameworkJobOptions {
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Add hooks.
|
25 |
+
*/
|
26 |
+
public function init() {
|
27 |
+
// Register our cleanup routine to run regularly.
|
28 |
+
add_action( Heartbeat::DAILY, array( $this, 'clean_up_old_completed_options' ) );
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Delete old completed product sync job rows from options table.
|
33 |
+
*
|
34 |
+
* Logic and database query are adapted from SV_WP_Background_Job_Handler::get_jobs().
|
35 |
+
*
|
36 |
+
* @see SV_WP_Background_Job_Handler
|
37 |
+
* @see Products\Sync\Background
|
38 |
+
*/
|
39 |
+
public function clean_up_old_completed_options() {
|
40 |
+
global $wpdb;
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Query notes:
|
44 |
+
* - Matching product sync job only (Products\Sync\Background class).
|
45 |
+
* - Matching "completed" status by sniffing json option value.
|
46 |
+
* - Order by lowest id, to delete older rows first.
|
47 |
+
* - Limit number of rows (periodic task will eventually remove all).
|
48 |
+
* Using `get_results` so we can limit number of items; `delete` doesn't allow this.
|
49 |
+
*/
|
50 |
+
$wpdb->query(
|
51 |
+
"DELETE
|
52 |
+
FROM {$wpdb->options}
|
53 |
+
WHERE option_name LIKE 'wc_facebook_background_product_sync_job_%'
|
54 |
+
AND option_value LIKE '%\"status\":\"completed\"%'
|
55 |
+
ORDER BY option_id ASC
|
56 |
+
LIMIT 250"
|
57 |
+
);
|
58 |
+
}
|
59 |
+
|
60 |
+
}
|
includes/Jobs/JobRegistry.php
CHANGED
@@ -18,6 +18,11 @@ class JobRegistry {
|
|
18 |
*/
|
19 |
public $generate_product_feed_job;
|
20 |
|
|
|
|
|
|
|
|
|
|
|
21 |
/**
|
22 |
* Instantiate and init all jobs for the plugin.
|
23 |
*/
|
@@ -26,6 +31,9 @@ class JobRegistry {
|
|
26 |
|
27 |
$this->generate_product_feed_job = new GenerateProductFeed( $action_scheduler_proxy );
|
28 |
$this->generate_product_feed_job->init();
|
|
|
|
|
|
|
29 |
}
|
30 |
|
31 |
}
|
18 |
*/
|
19 |
public $generate_product_feed_job;
|
20 |
|
21 |
+
/**
|
22 |
+
* @var CleanupSkyvergeFrameworkJobOptions
|
23 |
+
*/
|
24 |
+
public $cleanup_skyverge_job_options;
|
25 |
+
|
26 |
/**
|
27 |
* Instantiate and init all jobs for the plugin.
|
28 |
*/
|
31 |
|
32 |
$this->generate_product_feed_job = new GenerateProductFeed( $action_scheduler_proxy );
|
33 |
$this->generate_product_feed_job->init();
|
34 |
+
|
35 |
+
$this->cleanup_skyverge_job_options = new CleanupSkyvergeFrameworkJobOptions();
|
36 |
+
$this->cleanup_skyverge_job_options->init();
|
37 |
}
|
38 |
|
39 |
}
|
includes/ProductSync/ProductExcludedException.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace SkyVerge\WooCommerce\Facebook\ProductSync;
|
4 |
+
|
5 |
+
use Exception;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Class ProductExcludedException
|
9 |
+
*
|
10 |
+
* Exception for when a product is excluded from Facebook product sync.
|
11 |
+
*/
|
12 |
+
class ProductExcludedException extends Exception {}
|
includes/ProductSync/ProductValidator.php
ADDED
@@ -0,0 +1,259 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace SkyVerge\WooCommerce\Facebook\ProductSync;
|
4 |
+
|
5 |
+
use SkyVerge\WooCommerce\Facebook\Products;
|
6 |
+
use WC_Product;
|
7 |
+
use WC_Facebookcommerce_Integration;
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Class ProductValidator
|
11 |
+
*
|
12 |
+
* This class is responsible for validating whether a product should be synced to Facebook.
|
13 |
+
*
|
14 |
+
* @since 2.5.0
|
15 |
+
*/
|
16 |
+
class ProductValidator {
|
17 |
+
|
18 |
+
/**
|
19 |
+
* The meta key used to flag whether a product should be synced in Facebook
|
20 |
+
*
|
21 |
+
* @var string
|
22 |
+
*/
|
23 |
+
const SYNC_ENABLED_META_KEY = '_wc_facebook_sync_enabled';
|
24 |
+
|
25 |
+
/**
|
26 |
+
* The FB integration instance.
|
27 |
+
*
|
28 |
+
* @var WC_Facebookcommerce_Integration
|
29 |
+
*/
|
30 |
+
protected $integration;
|
31 |
+
|
32 |
+
/**
|
33 |
+
* The product object to validate.
|
34 |
+
*
|
35 |
+
* @var WC_Product
|
36 |
+
*/
|
37 |
+
protected $product;
|
38 |
+
|
39 |
+
/**
|
40 |
+
* The product parent object if the product has a parent.
|
41 |
+
*
|
42 |
+
* @var WC_Product
|
43 |
+
*/
|
44 |
+
protected $product_parent;
|
45 |
+
|
46 |
+
/**
|
47 |
+
* ProductValidator constructor.
|
48 |
+
*
|
49 |
+
* @param WC_Facebookcommerce_Integration $integration The FB integration instance.
|
50 |
+
* @param WC_Product $product The product to validate. Accepts both variations and variable products.
|
51 |
+
*/
|
52 |
+
public function __construct( WC_Facebookcommerce_Integration $integration, WC_Product $product ) {
|
53 |
+
$this->product = $product;
|
54 |
+
|
55 |
+
if ( $product->get_parent_id() ) {
|
56 |
+
$parent_product = wc_get_product( $product->get_parent_id() );
|
57 |
+
if ( $parent_product instanceof WC_Product ) {
|
58 |
+
$this->product_parent = $parent_product;
|
59 |
+
}
|
60 |
+
}
|
61 |
+
|
62 |
+
$this->integration = $integration;
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Validate whether the product should be synced to Facebook.
|
67 |
+
*
|
68 |
+
* @throws ProductExcludedException If product should not be synced.
|
69 |
+
*/
|
70 |
+
public function validate() {
|
71 |
+
$this->validate_sync_enabled_globally();
|
72 |
+
$this->validate_product_status();
|
73 |
+
$this->validate_product_stock_status();
|
74 |
+
$this->validate_product_sync_field();
|
75 |
+
$this->validate_product_price();
|
76 |
+
$this->validate_product_visibility();
|
77 |
+
$this->validate_product_terms();
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Validate whether the product should be synced to Facebook but skip the status check for backwards compatibility.
|
82 |
+
*
|
83 |
+
* @internal Do not use this as it will likely be removed.
|
84 |
+
*
|
85 |
+
* @throws ProductExcludedException If product should not be synced.
|
86 |
+
*/
|
87 |
+
public function validate_but_skip_status_check() {
|
88 |
+
$this->validate_sync_enabled_globally();
|
89 |
+
$this->validate_product_stock_status();
|
90 |
+
$this->validate_product_sync_field();
|
91 |
+
$this->validate_product_price();
|
92 |
+
$this->validate_product_visibility();
|
93 |
+
$this->validate_product_terms();
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Validate whether the product should be synced to Facebook.
|
98 |
+
*
|
99 |
+
* @return bool
|
100 |
+
*/
|
101 |
+
public function passes_all_checks(): bool {
|
102 |
+
try {
|
103 |
+
$this->validate();
|
104 |
+
} catch ( ProductExcludedException $e ) {
|
105 |
+
return false;
|
106 |
+
}
|
107 |
+
|
108 |
+
return true;
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Check if the product's terms (categories and tags) allow it to sync.
|
113 |
+
*
|
114 |
+
* @return bool
|
115 |
+
*/
|
116 |
+
public function passes_product_terms_check(): bool {
|
117 |
+
try {
|
118 |
+
$this->validate_product_terms();
|
119 |
+
} catch ( ProductExcludedException $e ) {
|
120 |
+
return false;
|
121 |
+
}
|
122 |
+
|
123 |
+
return true;
|
124 |
+
}
|
125 |
+
|
126 |
+
/**
|
127 |
+
* Check if the product's product sync meta field allows it to sync.
|
128 |
+
*
|
129 |
+
* @return bool
|
130 |
+
*/
|
131 |
+
public function passes_product_sync_field_check(): bool {
|
132 |
+
try {
|
133 |
+
$this->validate_product_sync_field();
|
134 |
+
} catch ( ProductExcludedException $e ) {
|
135 |
+
return false;
|
136 |
+
}
|
137 |
+
|
138 |
+
return true;
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Check whether product sync is globally disabled.
|
143 |
+
*
|
144 |
+
* @throws ProductExcludedException If product should not be synced.
|
145 |
+
*/
|
146 |
+
protected function validate_sync_enabled_globally() {
|
147 |
+
if ( ! $this->integration->is_product_sync_enabled() ) {
|
148 |
+
throw new ProductExcludedException( __( 'Product sync is globally disabled.', 'facebook-for-woocommerce' ) );
|
149 |
+
}
|
150 |
+
}
|
151 |
+
|
152 |
+
/**
|
153 |
+
* Check whether the product's status excludes it from sync.
|
154 |
+
*
|
155 |
+
* @throws ProductExcludedException If product should not be synced.
|
156 |
+
*/
|
157 |
+
protected function validate_product_status() {
|
158 |
+
$product = $this->product_parent ? $this->product_parent : $this->product;
|
159 |
+
|
160 |
+
if ( 'publish' !== $product->get_status() ) {
|
161 |
+
throw new ProductExcludedException( __( 'Product is not published.', 'facebook-for-woocommerce' ) );
|
162 |
+
}
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Check whether the product should be excluded due to being out of stock.
|
167 |
+
*
|
168 |
+
* @throws ProductExcludedException If product should not be synced.
|
169 |
+
*/
|
170 |
+
protected function validate_product_stock_status() {
|
171 |
+
if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && ! $this->product->is_in_stock() ) {
|
172 |
+
throw new ProductExcludedException( __( 'Product must be in stock.', 'facebook-for-woocommerce' ) );
|
173 |
+
}
|
174 |
+
}
|
175 |
+
|
176 |
+
/**
|
177 |
+
* Check whether the product's visibility excludes it from sync.
|
178 |
+
*
|
179 |
+
* Products are excluded if they are hidden from the store catalog or from search results.
|
180 |
+
*
|
181 |
+
* @throws ProductExcludedException If product should not be synced.
|
182 |
+
*/
|
183 |
+
protected function validate_product_visibility() {
|
184 |
+
$product = $this->product_parent ? $this->product_parent : $this->product;
|
185 |
+
|
186 |
+
if ( 'visible' !== $product->get_catalog_visibility() ) {
|
187 |
+
throw new ProductExcludedException( __( 'Product is hidden from catalog and search.', 'facebook-for-woocommerce' ) );
|
188 |
+
}
|
189 |
+
}
|
190 |
+
|
191 |
+
/**
|
192 |
+
* Check whether the product's categories or tags (terms) exclude it from sync.
|
193 |
+
*
|
194 |
+
* @throws ProductExcludedException If product should not be synced.
|
195 |
+
*/
|
196 |
+
protected function validate_product_terms() {
|
197 |
+
$product = $this->product_parent ? $this->product_parent : $this->product;
|
198 |
+
|
199 |
+
$excluded_categories = $this->integration->get_excluded_product_category_ids();
|
200 |
+
if ( $excluded_categories ) {
|
201 |
+
if ( ! empty( array_intersect( $product->get_category_ids(), $excluded_categories ) ) ) {
|
202 |
+
throw new ProductExcludedException( __( 'Product excluded because of categories.', 'facebook-for-woocommerce' ) );
|
203 |
+
}
|
204 |
+
}
|
205 |
+
|
206 |
+
$excluded_tags = $this->integration->get_excluded_product_tag_ids();
|
207 |
+
if ( $excluded_tags ) {
|
208 |
+
if ( ! empty( array_intersect( $product->get_tag_ids(), $excluded_tags ) ) ) {
|
209 |
+
throw new ProductExcludedException( __( 'Product excluded because of tags.', 'facebook-for-woocommerce' ) );
|
210 |
+
}
|
211 |
+
}
|
212 |
+
}
|
213 |
+
|
214 |
+
/**
|
215 |
+
* Validate if the product is excluded from at the "product level" (product meta value).
|
216 |
+
*
|
217 |
+
* @throws ProductExcludedException If product should not be synced.
|
218 |
+
*/
|
219 |
+
protected function validate_product_sync_field() {
|
220 |
+
$invalid_exception = new ProductExcludedException( __( 'Sync disabled in product field.', 'facebook-for-woocommerce' ) );
|
221 |
+
|
222 |
+
if ( $this->product->is_type( 'variable' ) ) {
|
223 |
+
foreach ( $this->product->get_children() as $child_id ) {
|
224 |
+
$child_product = wc_get_product( $child_id );
|
225 |
+
if ( $child_product && 'no' !== $child_product->get_meta( self::SYNC_ENABLED_META_KEY ) ) {
|
226 |
+
// At least one product is "sync-enabled" so bail before exception.
|
227 |
+
return;
|
228 |
+
}
|
229 |
+
}
|
230 |
+
|
231 |
+
// Variable product has no variations with sync enabled so it shouldn't be synced.
|
232 |
+
throw $invalid_exception;
|
233 |
+
} else {
|
234 |
+
if ( 'no' === $this->product->get_meta( self::SYNC_ENABLED_META_KEY ) ) {
|
235 |
+
throw $invalid_exception;
|
236 |
+
}
|
237 |
+
}
|
238 |
+
}
|
239 |
+
|
240 |
+
/**
|
241 |
+
* "allow simple or variable products (and their variations) with zero or empty price - exclude other product types with zero or empty price"
|
242 |
+
* unsure why but that's what we're doing
|
243 |
+
*
|
244 |
+
* @throws ProductExcludedException If product should not be synced.
|
245 |
+
*/
|
246 |
+
protected function validate_product_price() {
|
247 |
+
$primary_product = $this->product_parent ? $this->product_parent : $this->product;
|
248 |
+
|
249 |
+
// Variable and simple products are allowed to have no price.
|
250 |
+
if ( in_array( $primary_product->get_type(), array( 'simple', 'variable' ), true ) ) {
|
251 |
+
return;
|
252 |
+
}
|
253 |
+
|
254 |
+
if ( ! Products::get_product_price( $this->product ) ) {
|
255 |
+
throw new ProductExcludedException( __( 'If product is not simple, variable or variation it must have a price.', 'facebook-for-woocommerce' ) );
|
256 |
+
}
|
257 |
+
}
|
258 |
+
|
259 |
+
}
|
includes/Products.php
CHANGED
@@ -64,10 +64,6 @@ class Products {
|
|
64 |
/** @var string the meta key used to store the name of the pattern attribute for a product */
|
65 |
const PATTERN_ATTRIBUTE_META_KEY = '_wc_facebook_pattern_attribute';
|
66 |
|
67 |
-
|
68 |
-
/** @var array memoized array of sync enabled status for products */
|
69 |
-
private static $products_sync_enabled = array();
|
70 |
-
|
71 |
/** @var array memoized array of visibility status for products */
|
72 |
private static $products_visibility = array();
|
73 |
|
@@ -81,9 +77,6 @@ class Products {
|
|
81 |
* @param bool $enabled whether sync should be enabled for $products
|
82 |
*/
|
83 |
private static function set_sync_for_products( array $products, $enabled ) {
|
84 |
-
|
85 |
-
self::$products_sync_enabled = array();
|
86 |
-
|
87 |
$enabled = wc_bool_to_string( $enabled );
|
88 |
|
89 |
foreach ( $products as $product ) {
|
@@ -193,7 +186,7 @@ class Products {
|
|
193 |
/**
|
194 |
* Determines whether the given product should be synced.
|
195 |
*
|
196 |
-
* @
|
197 |
*
|
198 |
* @since 1.10.0
|
199 |
*
|
@@ -201,8 +194,12 @@ class Products {
|
|
201 |
* @return bool
|
202 |
*/
|
203 |
public static function product_should_be_synced( \WC_Product $product ) {
|
204 |
-
|
205 |
-
|
|
|
|
|
|
|
|
|
206 |
}
|
207 |
|
208 |
|
@@ -211,8 +208,7 @@ class Products {
|
|
211 |
*
|
212 |
* If a product is enabled for sync, but belongs to an excluded term, it will return as excluded from sync:
|
213 |
*
|
214 |
-
* @
|
215 |
-
* @see Products::is_sync_excluded_for_product_terms()
|
216 |
*
|
217 |
* @since 2.0.0-dev.1
|
218 |
*
|
@@ -220,32 +216,12 @@ class Products {
|
|
220 |
* @return bool
|
221 |
*/
|
222 |
public static function published_product_should_be_synced( \WC_Product $product ) {
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
$terms_product = $product->is_type( 'variation' ) ? wc_get_product( $product->get_parent_id() ) : $product;
|
229 |
-
} else {
|
230 |
-
$terms_product = null;
|
231 |
-
}
|
232 |
-
|
233 |
-
// allow simple or variable products (and their variations) with zero or empty price - exclude other product types with zero or empty price
|
234 |
-
if ( $should_sync && ( ! $terms_product || ( ! self::get_product_price( $product ) && ! in_array( $terms_product->get_type(), array( 'simple', 'variable' ) ) ) ) ) {
|
235 |
-
$should_sync = false;
|
236 |
-
}
|
237 |
-
|
238 |
-
// exclude products that are excluded from the store catalog or from search results
|
239 |
-
if ( $should_sync && ( ! $terms_product || has_term( array( 'exclude-from-catalog', 'exclude-from-search' ), 'product_visibility', $terms_product->get_id() ) ) ) {
|
240 |
-
$should_sync = false;
|
241 |
-
}
|
242 |
-
|
243 |
-
// exclude products that belong to one of the excluded terms
|
244 |
-
if ( $should_sync && ( ! $terms_product || self::is_sync_excluded_for_product_terms( $terms_product ) ) ) {
|
245 |
-
$should_sync = false;
|
246 |
}
|
247 |
-
|
248 |
-
return $should_sync;
|
249 |
}
|
250 |
|
251 |
|
@@ -271,39 +247,15 @@ class Products {
|
|
271 |
* If the product is not explicitly set to disable sync, it'll be considered enabled.
|
272 |
* This applies to products that may not have the meta value set.
|
273 |
*
|
|
|
|
|
274 |
* @since 1.10.0
|
275 |
*
|
276 |
* @param \WC_Product $product product object
|
277 |
* @return bool
|
278 |
*/
|
279 |
public static function is_sync_enabled_for_product( \WC_Product $product ) {
|
280 |
-
|
281 |
-
if ( ! isset( self::$products_sync_enabled[ $product->get_id() ] ) ) {
|
282 |
-
|
283 |
-
if ( $product->is_type( 'variable' ) ) {
|
284 |
-
|
285 |
-
// assume variable products are not synced until a synced child is found
|
286 |
-
$enabled = false;
|
287 |
-
|
288 |
-
foreach ( $product->get_children() as $child_id ) {
|
289 |
-
|
290 |
-
$child_product = wc_get_product( $child_id );
|
291 |
-
|
292 |
-
if ( $child_product && self::is_sync_enabled_for_product( $child_product ) ) {
|
293 |
-
|
294 |
-
$enabled = true;
|
295 |
-
break;
|
296 |
-
}
|
297 |
-
}
|
298 |
-
} else {
|
299 |
-
|
300 |
-
$enabled = 'no' !== $product->get_meta( self::SYNC_ENABLED_META_KEY );
|
301 |
-
}
|
302 |
-
|
303 |
-
self::$products_sync_enabled[ $product->get_id() ] = $enabled;
|
304 |
-
}//end if
|
305 |
-
|
306 |
-
return self::$products_sync_enabled[ $product->get_id() ];
|
307 |
}
|
308 |
|
309 |
|
@@ -312,26 +264,13 @@ class Products {
|
|
312 |
*
|
313 |
* @since 1.10.0
|
314 |
*
|
|
|
|
|
315 |
* @param \WC_Product $product product object
|
316 |
* @return bool if true, product should be excluded from sync, if false, product can be included in sync (unless manually excluded by individual product meta)
|
317 |
*/
|
318 |
public static function is_sync_excluded_for_product_terms( \WC_Product $product ) {
|
319 |
-
|
320 |
-
if ( $integration = facebook_for_woocommerce()->get_integration() ) {
|
321 |
-
$excluded_categories = $integration->get_excluded_product_category_ids();
|
322 |
-
$excluded_tags = $integration->get_excluded_product_tag_ids();
|
323 |
-
} else {
|
324 |
-
$excluded_categories = $excluded_tags = array();
|
325 |
-
}
|
326 |
-
|
327 |
-
$categories = $product->get_category_ids();
|
328 |
-
$tags = $product->get_tag_ids();
|
329 |
-
|
330 |
-
// returns true if no terms on the product, or no terms excluded, or if the product does not contain any of the excluded terms
|
331 |
-
$matches = ( ! $categories || ! $excluded_categories || ! array_intersect( $categories, $excluded_categories ) )
|
332 |
-
&& ( ! $tags || ! $excluded_tags || ! array_intersect( $tags, $excluded_tags ) );
|
333 |
-
|
334 |
-
return ! $matches;
|
335 |
}
|
336 |
|
337 |
|
64 |
/** @var string the meta key used to store the name of the pattern attribute for a product */
|
65 |
const PATTERN_ATTRIBUTE_META_KEY = '_wc_facebook_pattern_attribute';
|
66 |
|
|
|
|
|
|
|
|
|
67 |
/** @var array memoized array of visibility status for products */
|
68 |
private static $products_visibility = array();
|
69 |
|
77 |
* @param bool $enabled whether sync should be enabled for $products
|
78 |
*/
|
79 |
private static function set_sync_for_products( array $products, $enabled ) {
|
|
|
|
|
|
|
80 |
$enabled = wc_bool_to_string( $enabled );
|
81 |
|
82 |
foreach ( $products as $product ) {
|
186 |
/**
|
187 |
* Determines whether the given product should be synced.
|
188 |
*
|
189 |
+
* @deprecated use \SkyVerge\WooCommerce\Facebook\ProductSync\ProductValidator::validate() instead
|
190 |
*
|
191 |
* @since 1.10.0
|
192 |
*
|
194 |
* @return bool
|
195 |
*/
|
196 |
public static function product_should_be_synced( \WC_Product $product ) {
|
197 |
+
try {
|
198 |
+
facebook_for_woocommerce()->get_product_sync_validator( $product )->validate();
|
199 |
+
return true;
|
200 |
+
} catch ( \Exception $e ) {
|
201 |
+
return false;
|
202 |
+
}
|
203 |
}
|
204 |
|
205 |
|
208 |
*
|
209 |
* If a product is enabled for sync, but belongs to an excluded term, it will return as excluded from sync:
|
210 |
*
|
211 |
+
* @deprecated use \SkyVerge\WooCommerce\Facebook\ProductSync\ProductValidator::validate() instead
|
|
|
212 |
*
|
213 |
* @since 2.0.0-dev.1
|
214 |
*
|
216 |
* @return bool
|
217 |
*/
|
218 |
public static function published_product_should_be_synced( \WC_Product $product ) {
|
219 |
+
try {
|
220 |
+
facebook_for_woocommerce()->get_product_sync_validator( $product )->validate_but_skip_status_check();
|
221 |
+
return true;
|
222 |
+
} catch ( \Exception $e ) {
|
223 |
+
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
224 |
}
|
|
|
|
|
225 |
}
|
226 |
|
227 |
|
247 |
* If the product is not explicitly set to disable sync, it'll be considered enabled.
|
248 |
* This applies to products that may not have the meta value set.
|
249 |
*
|
250 |
+
* @deprecated use \SkyVerge\WooCommerce\Facebook\ProductSync\ProductValidator::passes_product_sync_field_check() instead
|
251 |
+
*
|
252 |
* @since 1.10.0
|
253 |
*
|
254 |
* @param \WC_Product $product product object
|
255 |
* @return bool
|
256 |
*/
|
257 |
public static function is_sync_enabled_for_product( \WC_Product $product ) {
|
258 |
+
return facebook_for_woocommerce()->get_product_sync_validator( $product )->passes_product_sync_field_check();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
259 |
}
|
260 |
|
261 |
|
264 |
*
|
265 |
* @since 1.10.0
|
266 |
*
|
267 |
+
* @deprecated use \SkyVerge\WooCommerce\Facebook\ProductSync\ProductValidator::passes_product_terms_check() instead
|
268 |
+
*
|
269 |
* @param \WC_Product $product product object
|
270 |
* @return bool if true, product should be excluded from sync, if false, product can be included in sync (unless manually excluded by individual product meta)
|
271 |
*/
|
272 |
public static function is_sync_excluded_for_product_terms( \WC_Product $product ) {
|
273 |
+
return ! facebook_for_woocommerce()->get_product_sync_validator( $product )->passes_product_terms_check();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
274 |
}
|
275 |
|
276 |
|
includes/Products/Feed.php
CHANGED
@@ -12,6 +12,7 @@ namespace SkyVerge\WooCommerce\Facebook\Products;
|
|
12 |
|
13 |
defined( 'ABSPATH' ) or exit;
|
14 |
|
|
|
15 |
use SkyVerge\WooCommerce\PluginFramework\v5_10_0 as Framework;
|
16 |
|
17 |
/**
|
@@ -54,7 +55,7 @@ class Feed {
|
|
54 |
private function add_hooks() {
|
55 |
|
56 |
// schedule the recurring feed generation
|
57 |
-
add_action(
|
58 |
|
59 |
// regenerate the product feed
|
60 |
add_action( self::GENERATE_FEED_ACTION, array( $this, 'regenerate_feed' ) );
|
@@ -74,6 +75,7 @@ class Feed {
|
|
74 |
public function handle_feed_data_request() {
|
75 |
|
76 |
\WC_Facebookcommerce_Utils::log( 'Facebook is requesting the product feed.' );
|
|
|
77 |
|
78 |
$feed_handler = new \WC_Facebook_Product_Feed();
|
79 |
$file_path = $feed_handler->get_file_path();
|
12 |
|
13 |
defined( 'ABSPATH' ) or exit;
|
14 |
|
15 |
+
use SkyVerge\WooCommerce\Facebook\Utilities\Heartbeat;
|
16 |
use SkyVerge\WooCommerce\PluginFramework\v5_10_0 as Framework;
|
17 |
|
18 |
/**
|
55 |
private function add_hooks() {
|
56 |
|
57 |
// schedule the recurring feed generation
|
58 |
+
add_action( Heartbeat::HOURLY, array( $this, 'schedule_feed_generation' ) );
|
59 |
|
60 |
// regenerate the product feed
|
61 |
add_action( self::GENERATE_FEED_ACTION, array( $this, 'regenerate_feed' ) );
|
75 |
public function handle_feed_data_request() {
|
76 |
|
77 |
\WC_Facebookcommerce_Utils::log( 'Facebook is requesting the product feed.' );
|
78 |
+
facebook_for_woocommerce()->get_tracker()->track_feed_file_requested();
|
79 |
|
80 |
$feed_handler = new \WC_Facebook_Product_Feed();
|
81 |
$file_path = $feed_handler->get_file_path();
|
includes/Utilities/Heartbeat.php
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace SkyVerge\WooCommerce\Facebook\Utilities;
|
4 |
+
|
5 |
+
use WC_Queue_Interface;
|
6 |
+
|
7 |
+
defined( 'ABSPATH' ) || exit;
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Class Heartbeat
|
11 |
+
*
|
12 |
+
* Responsible for scheduling cron heartbeat hooks. Currently there is a single hourly heartbeat:
|
13 |
+
* - `facebook_for_woocommerce_heartbeat_hourly`
|
14 |
+
*
|
15 |
+
* @since 2.6.0
|
16 |
+
*/
|
17 |
+
class Heartbeat {
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Hook name for hourly heartbeat.
|
21 |
+
*/
|
22 |
+
const HOURLY = 'facebook_for_woocommerce_hourly_heartbeat';
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Hook name for daily heartbeat.
|
26 |
+
*/
|
27 |
+
const DAILY = 'facebook_for_woocommerce_daily_heartbeat';
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @var string
|
31 |
+
*/
|
32 |
+
protected $hourly_cron_name = 'facebook_for_woocommerce_hourly_heartbeat_cron';
|
33 |
+
|
34 |
+
/**
|
35 |
+
* @var string
|
36 |
+
*/
|
37 |
+
protected $daily_cron_name = 'facebook_for_woocommerce_daily_heartbeat_cron';
|
38 |
+
|
39 |
+
/**
|
40 |
+
* @var WC_Queue_Interface
|
41 |
+
*/
|
42 |
+
protected $queue;
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Heartbeat constructor.
|
46 |
+
*
|
47 |
+
* @param WC_Queue_Interface $queue WC Action Scheduler proxy.
|
48 |
+
*/
|
49 |
+
public function __construct( WC_Queue_Interface $queue ) {
|
50 |
+
$this->queue = $queue;
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Add hooks.
|
55 |
+
*/
|
56 |
+
public function init() {
|
57 |
+
add_action( 'init', array( $this, 'schedule_cron_events' ) );
|
58 |
+
add_action( $this->hourly_cron_name, array( $this, 'schedule_hourly_action' ) );
|
59 |
+
add_action( $this->daily_cron_name, array( $this, 'schedule_daily_action' ) );
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Schedule heartbeat cron events.
|
64 |
+
*
|
65 |
+
* WP Cron events are stored in an auto-loaded option so the performance impact is much lower than checking and
|
66 |
+
* scheduling an Action Scheduler action.
|
67 |
+
*/
|
68 |
+
public function schedule_cron_events() {
|
69 |
+
if ( ! wp_next_scheduled( $this->hourly_cron_name ) ) {
|
70 |
+
wp_schedule_event( time(), 'hourly', $this->hourly_cron_name );
|
71 |
+
}
|
72 |
+
if ( ! wp_next_scheduled( $this->daily_cron_name ) ) {
|
73 |
+
wp_schedule_event( time(), 'daily', $this->daily_cron_name );
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Schedule the hourly heartbeat action to run immediately.
|
79 |
+
*
|
80 |
+
* Scheduling an action frees up WP Cron to process more jobs in the current request. Action Scheduler has greater
|
81 |
+
* throughput so running our checks there is better.
|
82 |
+
*/
|
83 |
+
public function schedule_hourly_action() {
|
84 |
+
$this->queue->add( self::HOURLY );
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Schedule the daily heartbeat action to run immediately.
|
89 |
+
*/
|
90 |
+
public function schedule_daily_action() {
|
91 |
+
$this->queue->add( self::DAILY );
|
92 |
+
}
|
93 |
+
|
94 |
+
|
95 |
+
}
|
includes/Utilities/Tracker.php
CHANGED
@@ -10,7 +10,7 @@
|
|
10 |
|
11 |
namespace SkyVerge\WooCommerce\Facebook\Utilities;
|
12 |
|
13 |
-
defined( 'ABSPATH' )
|
14 |
|
15 |
/**
|
16 |
* Class for adding diagnostic info to WooCommerce Tracker snapshot.
|
@@ -21,6 +21,41 @@ defined( 'ABSPATH' ) or exit;
|
|
21 |
*/
|
22 |
class Tracker {
|
23 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
/**
|
25 |
* Constructor.
|
26 |
*
|
@@ -45,8 +80,11 @@ class Tracker {
|
|
45 |
$data['extensions'] = array();
|
46 |
}
|
47 |
|
48 |
-
|
49 |
-
|
|
|
|
|
|
|
50 |
$connection_is_happy = false;
|
51 |
$connection_handler = facebook_for_woocommerce()->get_connection_handler();
|
52 |
if ( $connection_handler ) {
|
@@ -54,13 +92,101 @@ class Tracker {
|
|
54 |
}
|
55 |
$data['extensions']['facebook-for-woocommerce']['is-connected'] = wc_bool_to_string( $connection_is_happy );
|
56 |
|
57 |
-
|
58 |
-
|
|
|
|
|
|
|
59 |
$product_sync_enabled = facebook_for_woocommerce()->get_integration()->is_product_sync_enabled();
|
60 |
$data['extensions']['facebook-for-woocommerce']['product-sync-enabled'] = wc_bool_to_string( $product_sync_enabled );
|
61 |
$messenger_enabled = facebook_for_woocommerce()->get_integration()->is_messenger_enabled();
|
62 |
$data['extensions']['facebook-for-woocommerce']['messenger-enabled'] = wc_bool_to_string( $messenger_enabled );
|
63 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
return $data;
|
65 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
}
|
10 |
|
11 |
namespace SkyVerge\WooCommerce\Facebook\Utilities;
|
12 |
|
13 |
+
defined( 'ABSPATH' ) || exit;
|
14 |
|
15 |
/**
|
16 |
* Class for adding diagnostic info to WooCommerce Tracker snapshot.
|
21 |
*/
|
22 |
class Tracker {
|
23 |
|
24 |
+
/**
|
25 |
+
* Life time for transients used for temporary caching of values we want to add to tracker snapshot.
|
26 |
+
*
|
27 |
+
* @var string
|
28 |
+
*/
|
29 |
+
const TRANSIENT_WCTRACKER_LIFE_TIME = 2 * WEEK_IN_SECONDS;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Transient key name; how long it took to generate the most recent feed file, or zero if it failed.
|
33 |
+
*
|
34 |
+
* @var string
|
35 |
+
*/
|
36 |
+
const TRANSIENT_WCTRACKER_FEED_GENERATION_TIME = 'facebook_for_woocommerce_wctracker_feed_generation_time';
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Transient key name; true if feed has been requested by Facebook.
|
40 |
+
*
|
41 |
+
* @var string
|
42 |
+
*/
|
43 |
+
const TRANSIENT_WCTRACKER_FEED_REQUESTED = 'facebook_for_woocommerce_wctracker_feed_requested';
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Transient key name; stores various FBE business settings.
|
47 |
+
*
|
48 |
+
* @var string
|
49 |
+
*/
|
50 |
+
const TRANSIENT_WCTRACKER_FBE_BUSINESS_CONFIG = 'facebook_for_woocommerce_wctracker_fbe_business_config';
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Transient key name; stores feed (data source) settings for catalog sync.
|
54 |
+
*
|
55 |
+
* @var string
|
56 |
+
*/
|
57 |
+
const TRANSIENT_WCTRACKER_FB_FEED_CONFIG = 'facebook_for_woocommerce_wctracker_fb_feed_config';
|
58 |
+
|
59 |
/**
|
60 |
* Constructor.
|
61 |
*
|
80 |
$data['extensions'] = array();
|
81 |
}
|
82 |
|
83 |
+
/**
|
84 |
+
* Is the site connected?
|
85 |
+
*
|
86 |
+
* @since 2.3.4
|
87 |
+
*/
|
88 |
$connection_is_happy = false;
|
89 |
$connection_handler = facebook_for_woocommerce()->get_connection_handler();
|
90 |
if ( $connection_handler ) {
|
92 |
}
|
93 |
$data['extensions']['facebook-for-woocommerce']['is-connected'] = wc_bool_to_string( $connection_is_happy );
|
94 |
|
95 |
+
/**
|
96 |
+
* What features are enabled on this site?
|
97 |
+
*
|
98 |
+
* @since 2.3.4
|
99 |
+
*/
|
100 |
$product_sync_enabled = facebook_for_woocommerce()->get_integration()->is_product_sync_enabled();
|
101 |
$data['extensions']['facebook-for-woocommerce']['product-sync-enabled'] = wc_bool_to_string( $product_sync_enabled );
|
102 |
$messenger_enabled = facebook_for_woocommerce()->get_integration()->is_messenger_enabled();
|
103 |
$data['extensions']['facebook-for-woocommerce']['messenger-enabled'] = wc_bool_to_string( $messenger_enabled );
|
104 |
|
105 |
+
/**
|
106 |
+
* How long did the last feed generation take (or did it fail - 0)?
|
107 |
+
*
|
108 |
+
* @since 2.6.0
|
109 |
+
*/
|
110 |
+
$feed_generation_time = get_transient( self::TRANSIENT_WCTRACKER_FEED_GENERATION_TIME );
|
111 |
+
$data['extensions']['facebook-for-woocommerce']['feed-generation-time'] = floatval( $feed_generation_time );
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Has the feed file been requested since the last snapshot?
|
115 |
+
*
|
116 |
+
* @since 2.6.0
|
117 |
+
*/
|
118 |
+
$feed_file_requested = get_transient( self::TRANSIENT_WCTRACKER_FEED_REQUESTED );
|
119 |
+
$data['extensions']['facebook-for-woocommerce']['feed-file-requested'] = wc_bool_to_string( $feed_file_requested );
|
120 |
+
// Manually delete the transient. This prop tracks if feed has been requested _since last snapshot_.
|
121 |
+
delete_transient( self::TRANSIENT_WCTRACKER_FEED_REQUESTED );
|
122 |
+
|
123 |
+
/**
|
124 |
+
* Miscellaneous Facebook config settings.
|
125 |
+
*
|
126 |
+
* @since 2.6.0
|
127 |
+
*/
|
128 |
+
$config = get_transient( self::TRANSIENT_WCTRACKER_FBE_BUSINESS_CONFIG );
|
129 |
+
$data['extensions']['facebook-for-woocommerce']['instagram-shopping-enabled'] = wc_bool_to_string( $config ?: $config->ig_shopping_enabled );
|
130 |
+
$data['extensions']['facebook-for-woocommerce']['instagram-cta-enabled'] = wc_bool_to_string( $config ?: $config->ig_cta_enabled );
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Feed pull / upload settings configured in Facebook UI.
|
134 |
+
*
|
135 |
+
* @since 2.6.0
|
136 |
+
*/
|
137 |
+
$data['extensions']['facebook-for-woocommerce']['product-feed-config'] = get_transient( self::TRANSIENT_WCTRACKER_FB_FEED_CONFIG );
|
138 |
+
|
139 |
return $data;
|
140 |
}
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Update transient with feed file generation time (in seconds).
|
144 |
+
*
|
145 |
+
* Note this is used to clear the transient (set to -1) to track feed generation failure.
|
146 |
+
*
|
147 |
+
* @since 2.6.0
|
148 |
+
*/
|
149 |
+
public function track_feed_file_generation_time( $time_in_seconds ) {
|
150 |
+
set_transient( self::TRANSIENT_WCTRACKER_FEED_GENERATION_TIME, $time_in_seconds, self::TRANSIENT_WCTRACKER_LIFE_TIME );
|
151 |
+
}
|
152 |
+
|
153 |
+
/**
|
154 |
+
* Store the fact that the feed has been requested by Facebook in a transient.
|
155 |
+
* This will later be added to next tracker snapshot.
|
156 |
+
*
|
157 |
+
* @since 2.6.0
|
158 |
+
*/
|
159 |
+
public function track_feed_file_requested() {
|
160 |
+
set_transient( self::TRANSIENT_WCTRACKER_FEED_REQUESTED, true, self::TRANSIENT_WCTRACKER_LIFE_TIME );
|
161 |
+
}
|
162 |
+
|
163 |
+
/**
|
164 |
+
* Store some Facebook config settings for tracking.
|
165 |
+
*
|
166 |
+
* @param bool $ig_shopping_enabled True if Instagram Shopping is configured.
|
167 |
+
* @param bool $ig_cta_enabled True if `ig_cta` config option is enabled.
|
168 |
+
* @since 2.6.0
|
169 |
+
*/
|
170 |
+
public function track_facebook_business_config(
|
171 |
+
bool $ig_shopping_enabled,
|
172 |
+
bool $ig_cta_enabled
|
173 |
+
) {
|
174 |
+
$transient = array(
|
175 |
+
'ig_shopping_enabled' => $ig_shopping_enabled,
|
176 |
+
'ig_cta_enabled' => $ig_cta_enabled,
|
177 |
+
);
|
178 |
+
set_transient( self::TRANSIENT_WCTRACKER_FBE_BUSINESS_CONFIG, $transient, self::TRANSIENT_WCTRACKER_LIFE_TIME );
|
179 |
+
}
|
180 |
+
|
181 |
+
/**
|
182 |
+
* Store Facebook feed config for tracking.
|
183 |
+
*
|
184 |
+
* @param array $feed_settings Key-value array of settings to add to tracker snapshot.
|
185 |
+
* @since 2.6.0
|
186 |
+
*/
|
187 |
+
public function track_facebook_feed_config(
|
188 |
+
array $feed_settings
|
189 |
+
) {
|
190 |
+
set_transient( self::TRANSIENT_WCTRACKER_FB_FEED_CONFIG, $feed_settings, self::TRANSIENT_WCTRACKER_LIFE_TIME );
|
191 |
+
}
|
192 |
}
|
includes/fbgraph.php
CHANGED
@@ -473,11 +473,80 @@ if ( ! class_exists( 'WC_Facebookcommerce_Graph_API' ) ) :
|
|
473 |
|
474 |
public function create_feed( $facebook_catalog_id, $data ) {
|
475 |
$url = $this->build_url( $facebook_catalog_id, '/product_feeds' );
|
|
|
476 |
// success API call will return {id: <product feed id>}
|
477 |
// failure API will return {error: <error message>}
|
478 |
return self::_post( $url, $data );
|
479 |
}
|
480 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
481 |
public function get_upload_status( $facebook_upload_id ) {
|
482 |
$url = $this->build_url( $facebook_upload_id, '/?fields=end_time' );
|
483 |
// success API call will return
|
473 |
|
474 |
public function create_feed( $facebook_catalog_id, $data ) {
|
475 |
$url = $this->build_url( $facebook_catalog_id, '/product_feeds' );
|
476 |
+
$url = $this->get_feed_endpoint_url( $facebook_catalog_id );
|
477 |
// success API call will return {id: <product feed id>}
|
478 |
// failure API will return {error: <error message>}
|
479 |
return self::_post( $url, $data );
|
480 |
}
|
481 |
|
482 |
+
/**
|
483 |
+
* Get all feed configurations for a given catalog id.
|
484 |
+
*
|
485 |
+
* @see https://developers.facebook.com/docs/marketing-api/reference/product-feed/
|
486 |
+
* @since 2.6.0
|
487 |
+
*
|
488 |
+
* @param String $facebook_catalog_id Facebook Catalog Id.
|
489 |
+
* @return Array Facebook feeds configurations.
|
490 |
+
*/
|
491 |
+
public function read_feeds( $facebook_catalog_id ) {
|
492 |
+
$url = $this->get_feed_endpoint_url( $facebook_catalog_id );
|
493 |
+
return $this->_get( $url );
|
494 |
+
}
|
495 |
+
|
496 |
+
/**
|
497 |
+
* Get general info about a feed (data source) configured in Facebook Business.
|
498 |
+
*
|
499 |
+
* @see https://developers.facebook.com/docs/marketing-api/reference/product-feed/
|
500 |
+
* @since 2.6.0
|
501 |
+
*
|
502 |
+
* @param String $feed_id Feed Id.
|
503 |
+
* @return Array Facebook feeds configurations.
|
504 |
+
*/
|
505 |
+
public function read_feed_information( $feed_id ) {
|
506 |
+
$url = $this->build_url( $feed_id, '/?fields=id,name,schedule,update_schedule,uploads' );
|
507 |
+
return $this->_get( $url );
|
508 |
+
}
|
509 |
+
|
510 |
+
/**
|
511 |
+
* Get metadata about a feed (data source) configured in Facebook Business.
|
512 |
+
*
|
513 |
+
* @see https://developers.facebook.com/docs/marketing-api/reference/product-feed/
|
514 |
+
* @since 2.6.0
|
515 |
+
*
|
516 |
+
* @param String $feed_id Facebook Catalog Id.
|
517 |
+
* @return Array Facebook feed metadata.
|
518 |
+
*/
|
519 |
+
public function read_feed_metadata( $feed_id ) {
|
520 |
+
$url = $this->build_url( $feed_id, '/?fields=created_time,latest_upload,product_count,schedule,update_schedule' );
|
521 |
+
return $this->_get( $url );
|
522 |
+
}
|
523 |
+
|
524 |
+
/**
|
525 |
+
* Get metadata about a recent feed upload.
|
526 |
+
*
|
527 |
+
* @see https://developers.facebook.com/docs/marketing-api/reference/product-feed-upload/
|
528 |
+
* @since 2.6.0
|
529 |
+
*
|
530 |
+
* @param String $upload_id Feed Upload Id.
|
531 |
+
* @return Array Feed upload metadata.
|
532 |
+
*/
|
533 |
+
public function read_upload_metadata( $upload_id ) {
|
534 |
+
$url = $this->build_url( $upload_id, '/?fields=error_count,warning_count,num_detected_items,num_persisted_items,url' );
|
535 |
+
return $this->_get( $url );
|
536 |
+
}
|
537 |
+
|
538 |
+
/**
|
539 |
+
* Create product_feeds graph edge url.
|
540 |
+
*
|
541 |
+
* @since 2.6.0
|
542 |
+
*
|
543 |
+
* @param String $facebook_catalog_id Facebook Catalog Id.
|
544 |
+
* @return String Graph edge url.
|
545 |
+
*/
|
546 |
+
public function get_feed_endpoint_url( $facebook_catalog_id ) {
|
547 |
+
return $this->build_url( $facebook_catalog_id, '/product_feeds' );
|
548 |
+
}
|
549 |
+
|
550 |
public function get_upload_status( $facebook_upload_id ) {
|
551 |
$url = $this->build_url( $facebook_upload_id, '/?fields=end_time' );
|
552 |
// success API call will return
|
includes/fbproductfeed.php
CHANGED
@@ -101,6 +101,7 @@ if ( ! class_exists( 'WC_Facebook_Product_Feed' ) ) :
|
|
101 |
$this->generate_productfeed_file();
|
102 |
|
103 |
$generation_time = microtime( true ) - $start_time;
|
|
|
104 |
|
105 |
$this->set_feed_generation_time_with_decay( $generation_time );
|
106 |
|
@@ -109,6 +110,9 @@ if ( ! class_exists( 'WC_Facebook_Product_Feed' ) ) :
|
|
109 |
} catch ( \Exception $exception ) {
|
110 |
|
111 |
\WC_Facebookcommerce_Utils::log( $exception->getMessage() );
|
|
|
|
|
|
|
112 |
}
|
113 |
|
114 |
$profiling_logger->stop( 'generate_feed' );
|
101 |
$this->generate_productfeed_file();
|
102 |
|
103 |
$generation_time = microtime( true ) - $start_time;
|
104 |
+
facebook_for_woocommerce()->get_tracker()->track_feed_file_generation_time( $generation_time );
|
105 |
|
106 |
$this->set_feed_generation_time_with_decay( $generation_time );
|
107 |
|
110 |
} catch ( \Exception $exception ) {
|
111 |
|
112 |
\WC_Facebookcommerce_Utils::log( $exception->getMessage() );
|
113 |
+
// Feed generation failed - clear the generation time to track that there's an issue.
|
114 |
+
facebook_for_woocommerce()->get_tracker()->track_feed_file_generation_time( -1 );
|
115 |
+
|
116 |
}
|
117 |
|
118 |
$profiling_logger->stop( 'generate_feed' );
|
readme.txt
CHANGED
@@ -2,8 +2,8 @@
|
|
2 |
Contributors: facebook, automattic, woothemes
|
3 |
Tags: facebook, shop, catalog, advertise, pixel, product
|
4 |
Requires at least: 4.4
|
5 |
-
Tested up to: 5.
|
6 |
-
Stable tag: 2.
|
7 |
Requires PHP: 5.6 or greater
|
8 |
MySQL: 5.6 or greater
|
9 |
License: GPLv2 or later
|
@@ -39,7 +39,14 @@ When opening a bug on GitHub, please give us as many details as possible.
|
|
39 |
|
40 |
== Changelog ==
|
41 |
|
42 |
-
= 2.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
* Fix - Reinstate reset and delete functions in Facebook metabox on Edit product admin screen
|
44 |
|
45 |
= 2.5.0 - 2021-05-19 =
|
2 |
Contributors: facebook, automattic, woothemes
|
3 |
Tags: facebook, shop, catalog, advertise, pixel, product
|
4 |
Requires at least: 4.4
|
5 |
+
Tested up to: 5.7
|
6 |
+
Stable tag: 2.6.0
|
7 |
Requires PHP: 5.6 or greater
|
8 |
MySQL: 5.6 or greater
|
9 |
License: GPLv2 or later
|
39 |
|
40 |
== Changelog ==
|
41 |
|
42 |
+
= 2.6.0 - 2021-06-10 =
|
43 |
+
* Fix – Add cron heartbeat and use to offload feed generation from init / admin_init (performance) #1953
|
44 |
+
* Fix – Clean up background sync options (performance) #1962
|
45 |
+
* Dev – Add tracker props to understand usage of feed-based sync and other FB business config options #1972
|
46 |
+
* Dev – Configure release tooling to auto-update version numbers in code #1982
|
47 |
+
* Dev – Refactor code responsible for validating whether a product should be synced to FB into one place #19333
|
48 |
+
|
49 |
+
= 2.5.1 - 2021-05-28 =
|
50 |
* Fix - Reinstate reset and delete functions in Facebook metabox on Edit product admin screen
|
51 |
|
52 |
= 2.5.0 - 2021-05-19 =
|
vendor/autoload.php
CHANGED
@@ -4,4 +4,4 @@
|
|
4 |
|
5 |
require_once __DIR__ . '/composer/autoload_real.php';
|
6 |
|
7 |
-
return
|
4 |
|
5 |
require_once __DIR__ . '/composer/autoload_real.php';
|
6 |
|
7 |
+
return ComposerAutoloaderInitf259fca39ad059a7a2ae6e49ea65d16c::getLoader();
|
vendor/composer/autoload_real.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
// autoload_real.php @generated by Composer
|
4 |
|
5 |
-
class
|
6 |
{
|
7 |
private static $loader;
|
8 |
|
@@ -22,15 +22,15 @@ class ComposerAutoloaderInitf67523c78e13409ff91c41e965ab86c6
|
|
22 |
return self::$loader;
|
23 |
}
|
24 |
|
25 |
-
spl_autoload_register(array('
|
26 |
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
27 |
-
spl_autoload_unregister(array('
|
28 |
|
29 |
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
30 |
if ($useStaticLoader) {
|
31 |
require_once __DIR__ . '/autoload_static.php';
|
32 |
|
33 |
-
call_user_func(\Composer\Autoload\
|
34 |
} else {
|
35 |
$map = require __DIR__ . '/autoload_namespaces.php';
|
36 |
foreach ($map as $namespace => $path) {
|
2 |
|
3 |
// autoload_real.php @generated by Composer
|
4 |
|
5 |
+
class ComposerAutoloaderInitf259fca39ad059a7a2ae6e49ea65d16c
|
6 |
{
|
7 |
private static $loader;
|
8 |
|
22 |
return self::$loader;
|
23 |
}
|
24 |
|
25 |
+
spl_autoload_register(array('ComposerAutoloaderInitf259fca39ad059a7a2ae6e49ea65d16c', 'loadClassLoader'), true, true);
|
26 |
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
27 |
+
spl_autoload_unregister(array('ComposerAutoloaderInitf259fca39ad059a7a2ae6e49ea65d16c', 'loadClassLoader'));
|
28 |
|
29 |
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
30 |
if ($useStaticLoader) {
|
31 |
require_once __DIR__ . '/autoload_static.php';
|
32 |
|
33 |
+
call_user_func(\Composer\Autoload\ComposerStaticInitf259fca39ad059a7a2ae6e49ea65d16c::getInitializer($loader));
|
34 |
} else {
|
35 |
$map = require __DIR__ . '/autoload_namespaces.php';
|
36 |
foreach ($map as $namespace => $path) {
|
vendor/composer/autoload_static.php
CHANGED
@@ -4,7 +4,7 @@
|
|
4 |
|
5 |
namespace Composer\Autoload;
|
6 |
|
7 |
-
class
|
8 |
{
|
9 |
public static $prefixLengthsPsr4 = array (
|
10 |
'S' =>
|
@@ -39,8 +39,8 @@ class ComposerStaticInitf67523c78e13409ff91c41e965ab86c6
|
|
39 |
public static function getInitializer(ClassLoader $loader)
|
40 |
{
|
41 |
return \Closure::bind(function () use ($loader) {
|
42 |
-
$loader->prefixLengthsPsr4 =
|
43 |
-
$loader->prefixDirsPsr4 =
|
44 |
|
45 |
}, null, ClassLoader::class);
|
46 |
}
|
4 |
|
5 |
namespace Composer\Autoload;
|
6 |
|
7 |
+
class ComposerStaticInitf259fca39ad059a7a2ae6e49ea65d16c
|
8 |
{
|
9 |
public static $prefixLengthsPsr4 = array (
|
10 |
'S' =>
|
39 |
public static function getInitializer(ClassLoader $loader)
|
40 |
{
|
41 |
return \Closure::bind(function () use ($loader) {
|
42 |
+
$loader->prefixLengthsPsr4 = ComposerStaticInitf259fca39ad059a7a2ae6e49ea65d16c::$prefixLengthsPsr4;
|
43 |
+
$loader->prefixDirsPsr4 = ComposerStaticInitf259fca39ad059a7a2ae6e49ea65d16c::$prefixDirsPsr4;
|
44 |
|
45 |
}, null, ClassLoader::class);
|
46 |
}
|