Version Description
- 2021-11-03 =
- New - Memory improved feed generation process. #2099
- New - Add compatibility with the WooCommerce checkout block. #2095
- New - Track batched feed generation time in the tracker snapshots. #2104
- New - Track usage of the new style feed generator in the tracker snapshots. #2103
- New - Hide headers in logs for better visibility. #2093
- Dev - Update composer dependencies. #2090
- New - Add no synchronization reason to the product edit screen in the Facebook meta box. #1937
- Fix - Use published variations only for the default variation. #2091
Download this release
Release Info
Developer | automattic |
Plugin | Facebook for WooCommerce |
Version | 2.6.6 |
Comparing to | |
See all releases |
Code changes from version 2.6.5 to 2.6.6
- README.md +3 -0
- changelog.txt +11 -1
- class-wc-facebookcommerce.php +11 -1
- facebook-commerce-events-tracker.php +26 -20
- facebook-commerce.php +68 -139
- facebook-for-woocommerce.php +2 -2
- i18n/languages/facebook-for-woocommerce.pot +103 -61
- includes/Admin/Product_Sync_Meta_Box.php +146 -0
- includes/Admin/Settings_Screens/Connection.php +10 -1
- includes/Jobs/GenerateProductFeed.php +39 -42
- includes/ProductSync/ProductInvalidException.php +14 -0
- includes/ProductSync/ProductValidator.php +113 -1
- includes/Products/Feed.php +9 -5
- includes/Utilities/Tracker.php +96 -2
- includes/fbproduct.php +9 -3
- includes/fbproductfeed.php +96 -251
- readme.txt +13 -3
- vendor/autoload.php +1 -1
- vendor/composer/ClassLoader.php +139 -12
- vendor/composer/InstalledVersions.php +327 -250
- vendor/composer/autoload_real.php +5 -5
- vendor/composer/autoload_static.php +4 -4
- vendor/composer/installed.json +15 -14
- vendor/composer/installed.php +59 -62
- vendor/composer/installers/src/Composer/Installers/CakePHPInstaller.php +1 -0
- vendor/composer/installers/src/Composer/Installers/Installer.php +1 -0
- vendor/composer/installers/src/Composer/Installers/PantheonInstaller.php +12 -0
- vendor/woocommerce/action-scheduler-job-framework/CHANGELOG.md +10 -0
- vendor/woocommerce/action-scheduler-job-framework/README.md +30 -0
- vendor/woocommerce/action-scheduler-job-framework/src/AbstractChainedJob.php +10 -11
README.md
CHANGED
@@ -11,6 +11,9 @@ The best place to get support is the [WordPress.org Facebook for WooCommerce for
|
|
11 |
|
12 |
If you have a WooCommerce.com account, you can [start a chat or open a ticket on WooCommerce.com](https://woocommerce.com/my-account/create-a-ticket/).
|
13 |
|
|
|
|
|
|
|
14 |
## Development
|
15 |
### Developing
|
16 |
- Clone this repository into the `wp-content/plugins/` folder your WooCommerce development environment.
|
11 |
|
12 |
If you have a WooCommerce.com account, you can [start a chat or open a ticket on WooCommerce.com](https://woocommerce.com/my-account/create-a-ticket/).
|
13 |
|
14 |
+
### Logging
|
15 |
+
The plugin offers logging that can help debug various problems. You can enable debug mode in the main plugin settings panel under the `Enable debug mode` section.
|
16 |
+
By default plugin omits headers in the requests to make the logs more readable. If debugging with headers is necessary you can enable the headers in the logs by setting `wc_facebook_request_headers_in_debug_log` option to true.
|
17 |
## Development
|
18 |
### Developing
|
19 |
- Clone this repository into the `wp-content/plugins/` folder your WooCommerce development environment.
|
changelog.txt
CHANGED
@@ -1,6 +1,16 @@
|
|
1 |
*** Facebook for WooCommerce Changelog ***
|
2 |
|
3 |
-
2021-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
* Fix - Incorrect `is_readable()` usage when loading Integration classes.
|
5 |
* Tweak - WC 5.7 compatibility.
|
6 |
* Tweak - WP 5.8 compatibility.
|
1 |
*** Facebook for WooCommerce Changelog ***
|
2 |
|
3 |
+
2021-11-03 - version 2.6.6
|
4 |
+
* New - Memory improved feed generation process. #2099
|
5 |
+
* New - Add compatibility with the WooCommerce checkout block. #2095
|
6 |
+
* New - Track batched feed generation time in the tracker snapshots. #2104
|
7 |
+
* New - Track usage of the new style feed generator in the tracker snapshots. #2103
|
8 |
+
* New - Hide headers in logs for better visibility. #2093
|
9 |
+
* Dev - Update composer dependencies. #2090
|
10 |
+
* New - Add no synchronization reason to the product edit screen in the Facebook meta box. #1937
|
11 |
+
* Fix - Use published variations only for the default variation. #2091
|
12 |
+
|
13 |
+
2021-09-16 - version 2.6.5
|
14 |
* Fix - Incorrect `is_readable()` usage when loading Integration classes.
|
15 |
* Tweak - WC 5.7 compatibility.
|
16 |
* Tweak - WP 5.8 compatibility.
|
class-wc-facebookcommerce.php
CHANGED
@@ -435,7 +435,17 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
|
|
435 |
return;
|
436 |
}
|
437 |
|
438 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
439 |
}
|
440 |
|
441 |
/**
|
435 |
return;
|
436 |
}
|
437 |
|
438 |
+
// Maybe remove headers from the debug log.
|
439 |
+
if( ! $this->get_integration()->are_headers_requested_for_debug() ) {
|
440 |
+
unset( $request['headers'] );
|
441 |
+
unset( $response['headers'] );
|
442 |
+
}
|
443 |
+
|
444 |
+
$this->log( $this->get_api_log_message( $request ), $log_id );
|
445 |
+
|
446 |
+
if ( ! empty( $response ) ) {
|
447 |
+
$this->log( $this->get_api_log_message( $response ), $log_id );
|
448 |
+
}
|
449 |
}
|
450 |
|
451 |
/**
|
facebook-commerce-events-tracker.php
CHANGED
@@ -130,6 +130,9 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
|
|
130 |
add_action( 'woocommerce_checkout_update_order_meta', array( $this, 'inject_purchase_event' ) );
|
131 |
add_action( 'woocommerce_thankyou', array( $this, 'inject_purchase_event' ), 40 );
|
132 |
|
|
|
|
|
|
|
133 |
// TODO move this in some 3rd party plugin integrations handler at some point {FN 2020-03-20}
|
134 |
add_action( 'wpcf7_contact_form', array( $this, 'inject_lead_event_hook' ), 11 );
|
135 |
}
|
@@ -938,6 +941,29 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
|
|
938 |
$order->save_meta_data();
|
939 |
}
|
940 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
941 |
|
942 |
/**
|
943 |
* Triggers a Subscribe event when a given order contains subscription products.
|
@@ -981,26 +1007,6 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
|
|
981 |
}
|
982 |
|
983 |
|
984 |
-
/**
|
985 |
-
* Triggers a Purchase event.
|
986 |
-
*
|
987 |
-
* Duplicate of {@see \WC_Facebookcommerce_EventsTracker::inject_purchase_event()}
|
988 |
-
*
|
989 |
-
* TODO remove this deprecated method by version 2.0.0 or by March 2020 {FN 2020-03-20}
|
990 |
-
*
|
991 |
-
* @internal
|
992 |
-
* @deprecated since 1.11.0
|
993 |
-
*
|
994 |
-
* @param int $order_id order identifier
|
995 |
-
*/
|
996 |
-
public function inject_gateway_purchase_event( $order_id ) {
|
997 |
-
|
998 |
-
wc_deprecated_function( __METHOD__, '1.11.0', __CLASS__ . '::inject_purchase_event()' );
|
999 |
-
|
1000 |
-
$this->inject_purchase_event( $order_id );
|
1001 |
-
}
|
1002 |
-
|
1003 |
-
|
1004 |
/** Contact Form 7 Support **/
|
1005 |
public function inject_lead_event_hook() {
|
1006 |
add_action( 'wp_footer', array( $this, 'inject_lead_event' ), 11 );
|
130 |
add_action( 'woocommerce_checkout_update_order_meta', array( $this, 'inject_purchase_event' ) );
|
131 |
add_action( 'woocommerce_thankyou', array( $this, 'inject_purchase_event' ), 40 );
|
132 |
|
133 |
+
// Checkout update order meta from the Checkout Block.
|
134 |
+
add_action( '__experimental_woocommerce_blocks_checkout_update_order_meta', array( $this, 'inject_order_meta_event_for_checkout_block_flow' ) );
|
135 |
+
|
136 |
// TODO move this in some 3rd party plugin integrations handler at some point {FN 2020-03-20}
|
137 |
add_action( 'wpcf7_contact_form', array( $this, 'inject_lead_event_hook' ), 11 );
|
138 |
}
|
941 |
$order->save_meta_data();
|
942 |
}
|
943 |
|
944 |
+
/**
|
945 |
+
* Inject order meta gor WooCommerce Checkout Blocks flow.
|
946 |
+
* The blocks flow does not trigger the woocommerce_checkout_update_order_meta so we can't rely on it.
|
947 |
+
* The Checkout Block has its own ( so far ) experimental hook that allows us to inject the meta at
|
948 |
+
* the appropriate moment: __experimental_woocommerce_blocks_checkout_update_order_meta.
|
949 |
+
*
|
950 |
+
* @since 2.6.6
|
951 |
+
*
|
952 |
+
* @param WC_Order $order Order object.
|
953 |
+
*/
|
954 |
+
public function inject_order_meta_event_for_checkout_block_flow( $order ) {
|
955 |
+
|
956 |
+
$event_name = 'Purchase';
|
957 |
+
|
958 |
+
if ( ! $this->is_pixel_enabled() || $this->pixel->is_last_event( $event_name ) ) {
|
959 |
+
return;
|
960 |
+
}
|
961 |
+
|
962 |
+
$order_placed_meta = '_wc_' . facebook_for_woocommerce()->get_id() . '_order_placed';
|
963 |
+
$order->update_meta_data( $order_placed_meta, 'yes' );
|
964 |
+
$order->save_meta_data();
|
965 |
+
}
|
966 |
+
|
967 |
|
968 |
/**
|
969 |
* Triggers a Subscribe event when a given order contains subscription products.
|
1007 |
}
|
1008 |
|
1009 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1010 |
/** Contact Form 7 Support **/
|
1011 |
public function inject_lead_event_hook() {
|
1012 |
add_action( 'wp_footer', array( $this, 'inject_lead_event' ), 11 );
|
facebook-commerce.php
CHANGED
@@ -101,6 +101,12 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
|
|
101 |
/** @var string the "debug mode" setting ID */
|
102 |
const SETTING_ENABLE_DEBUG_MODE = 'wc_facebook_enable_debug_mode';
|
103 |
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
/** @var string the standard product description mode name */
|
105 |
const PRODUCT_DESCRIPTION_MODE_STANDARD = 'standard';
|
106 |
|
@@ -369,7 +375,7 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
|
|
369 |
|
370 |
add_action( 'before_delete_post', array( $this, 'on_product_delete' ) );
|
371 |
|
372 |
-
add_action( 'add_meta_boxes',
|
373 |
|
374 |
add_action(
|
375 |
'transition_post_status',
|
@@ -416,9 +422,6 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
|
|
416 |
// Must be outside of admin for cron to schedule correctly.
|
417 |
add_action( 'sync_all_fb_products_using_feed', array( $this, 'handle_scheduled_resync_action' ), self::FB_PRIORITY_MID );
|
418 |
|
419 |
-
// Handle the special background feed generation action.
|
420 |
-
add_action( 'wc_facebook_generate_product_catalog_feed', array( $this, 'handle_generate_product_catalog_feed' ) );
|
421 |
-
|
422 |
if ( $this->get_facebook_pixel_id() ) {
|
423 |
$aam_settings = $this->load_aam_settings_of_pixel();
|
424 |
$user_info = WC_Facebookcommerce_Utils::get_user_info( $aam_settings );
|
@@ -591,102 +594,6 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
|
|
591 |
wc_deprecated_function( __METHOD__, '1.10.0', '\\SkyVerge\\WooCommerce\\Facebook\\Admin::add_product_list_table_columns_content()' );
|
592 |
}
|
593 |
|
594 |
-
|
595 |
-
public function fb_product_metabox() {
|
596 |
-
$ajax_data = array(
|
597 |
-
'nonce' => wp_create_nonce( 'wc_facebook_metabox_jsx' ),
|
598 |
-
);
|
599 |
-
wp_enqueue_script(
|
600 |
-
'wc_facebook_metabox_jsx',
|
601 |
-
facebook_for_woocommerce()->get_asset_build_dir_url() . '/admin/metabox.js',
|
602 |
-
array(),
|
603 |
-
\WC_Facebookcommerce::PLUGIN_VERSION
|
604 |
-
);
|
605 |
-
wp_localize_script(
|
606 |
-
'wc_facebook_metabox_jsx',
|
607 |
-
'wc_facebook_metabox_jsx',
|
608 |
-
$ajax_data
|
609 |
-
);
|
610 |
-
|
611 |
-
add_meta_box(
|
612 |
-
'facebook_metabox', // Meta box ID
|
613 |
-
'Facebook', // Meta box Title
|
614 |
-
array( $this, 'fb_product_meta_box_html' ), // Callback
|
615 |
-
'product', // Screen to which to add the meta box
|
616 |
-
'side' // Context
|
617 |
-
);
|
618 |
-
}
|
619 |
-
|
620 |
-
|
621 |
-
/**
|
622 |
-
* Renders the content of the product meta box.
|
623 |
-
*/
|
624 |
-
public function fb_product_meta_box_html() {
|
625 |
-
global $post;
|
626 |
-
|
627 |
-
$woo_product = new WC_Facebook_Product( $post->ID );
|
628 |
-
$fb_product_group_id = null;
|
629 |
-
|
630 |
-
if ( $woo_product->woo_product instanceof \WC_Product && Products::product_should_be_synced( $woo_product->woo_product ) ) {
|
631 |
-
$fb_product_group_id = $this->get_product_fbid( self::FB_PRODUCT_GROUP_ID, $post->ID, $woo_product );
|
632 |
-
}
|
633 |
-
|
634 |
-
?>
|
635 |
-
<span id="fb_metadata">
|
636 |
-
<?php
|
637 |
-
|
638 |
-
if ( $fb_product_group_id ) {
|
639 |
-
|
640 |
-
?>
|
641 |
-
|
642 |
-
<?php echo esc_html__( 'Facebook ID:', 'facebook-for-woocommerce' ); ?> <a href="https://facebook.com/<?php echo esc_attr( $fb_product_group_id ); ?>"
|
643 |
-
target="_blank"><?php echo esc_html( $fb_product_group_id ); ?></a>
|
644 |
-
|
645 |
-
<?php if ( WC_Facebookcommerce_Utils::is_variable_type( $woo_product->get_type() ) ) : ?>
|
646 |
-
|
647 |
-
<?php if ( $product_item_ids_by_variation_id = $this->get_variation_product_item_ids( $woo_product, $fb_product_group_id ) ) : ?>
|
648 |
-
|
649 |
-
<p>
|
650 |
-
<?php echo esc_html__( 'Variant IDs:', 'facebook-for-woocommerce' ); ?><br/>
|
651 |
-
|
652 |
-
<?php foreach ( $product_item_ids_by_variation_id as $variation_id => $product_item_id ) : ?>
|
653 |
-
|
654 |
-
<?php echo esc_html( $variation_id ); ?>: <a href="https://facebook.com/<?php echo esc_attr( $product_item_id ); ?>"
|
655 |
-
target="_blank"><?php echo esc_html( $product_item_id ); ?></a><br/>
|
656 |
-
|
657 |
-
<?php endforeach; ?>
|
658 |
-
</p>
|
659 |
-
|
660 |
-
<?php endif; ?>
|
661 |
-
|
662 |
-
<?php endif; ?>
|
663 |
-
|
664 |
-
<input name="is_product_page" type="hidden" value="1"/>
|
665 |
-
|
666 |
-
<p/>
|
667 |
-
<a href="#" onclick="fb_reset_product( <?php echo esc_js( $post->ID ); ?> )">
|
668 |
-
<?php echo esc_html__( 'Reset Facebook metadata', 'facebook-for-woocommerce' ); ?>
|
669 |
-
</a>
|
670 |
-
|
671 |
-
<p/>
|
672 |
-
<a href="#" onclick="fb_delete_product( <?php echo esc_js( $post->ID ); ?> )">
|
673 |
-
<?php echo esc_html__( 'Delete product(s) on Facebook', 'facebook-for-woocommerce' ); ?>
|
674 |
-
</a>
|
675 |
-
|
676 |
-
<?php
|
677 |
-
|
678 |
-
} else {
|
679 |
-
|
680 |
-
?>
|
681 |
-
<b><?php echo esc_html__( 'This product is not yet synced to Facebook.', 'facebook-for-woocommerce' ); ?></b>
|
682 |
-
<?php
|
683 |
-
}
|
684 |
-
|
685 |
-
?>
|
686 |
-
</span>
|
687 |
-
<?php
|
688 |
-
}
|
689 |
-
|
690 |
/**
|
691 |
* Returns graph API client object.
|
692 |
*
|
@@ -706,7 +613,7 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
|
|
706 |
* @param string $product_group_id product group ID
|
707 |
* @return array
|
708 |
*/
|
709 |
-
|
710 |
|
711 |
$product_item_ids_by_variation_id = array();
|
712 |
$missing_product_item_ids = array();
|
@@ -1515,21 +1422,14 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
|
|
1515 |
return;
|
1516 |
}
|
1517 |
|
1518 |
-
// figure out the matching default variation
|
1519 |
-
$default_product_fbid = null;
|
1520 |
-
$woo_default_variation = $this->get_product_group_default_variation( $woo_product );
|
1521 |
-
|
1522 |
-
if ( $woo_default_variation ) {
|
1523 |
-
$default_product_fbid = $this->get_product_fbid(
|
1524 |
-
self::FB_PRODUCT_ITEM_ID,
|
1525 |
-
$woo_default_variation['variation_id']
|
1526 |
-
);
|
1527 |
-
}
|
1528 |
|
1529 |
$product_group_data = array(
|
1530 |
'variants' => $variants,
|
1531 |
);
|
1532 |
|
|
|
|
|
|
|
1533 |
if ( $default_product_fbid ) {
|
1534 |
$product_group_data['default_product_id'] = $default_product_fbid;
|
1535 |
}
|
@@ -1555,13 +1455,17 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
|
|
1555 |
|
1556 |
/**
|
1557 |
* Determines if there is a matching variation for the default attributes.
|
|
|
|
|
|
|
|
|
1558 |
*
|
1559 |
* @since 2.1.2
|
1560 |
*
|
1561 |
* @param \WC_Facebook_Product $woo_product
|
1562 |
-
* @return
|
1563 |
*/
|
1564 |
-
private function get_product_group_default_variation( $woo_product ) {
|
1565 |
|
1566 |
$default_attributes = $woo_product->woo_product->get_default_attributes( 'edit' );
|
1567 |
|
@@ -1569,19 +1473,41 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
|
|
1569 |
return null;
|
1570 |
}
|
1571 |
|
1572 |
-
$default_variation
|
1573 |
-
|
|
|
|
|
|
|
|
|
1574 |
|
|
|
1575 |
foreach ( $product_variations as $variation ) {
|
1576 |
|
1577 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1578 |
|
1579 |
-
$
|
|
|
|
|
1580 |
|
1581 |
-
|
1582 |
-
|
|
|
|
|
1583 |
break;
|
|
|
|
|
|
|
1584 |
}
|
|
|
1585 |
}
|
1586 |
|
1587 |
return $default_variation;
|
@@ -3267,6 +3193,29 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
|
|
3267 |
return (bool) apply_filters( 'wc_facebook_is_debug_mode_enabled', 'yes' === get_option( self::SETTING_ENABLE_DEBUG_MODE ), $this );
|
3268 |
}
|
3269 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3270 |
|
3271 |
/***
|
3272 |
* Determines if the feed has been migrated from FBE 1 to FBE 1.5
|
@@ -3870,26 +3819,6 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
|
|
3870 |
}
|
3871 |
}
|
3872 |
|
3873 |
-
/**
|
3874 |
-
* Handles the schedule feed generation action, triggered by the REST API.
|
3875 |
-
*
|
3876 |
-
* @since 1.11.0
|
3877 |
-
*/
|
3878 |
-
public function handle_generate_product_catalog_feed() {
|
3879 |
-
|
3880 |
-
$feed_handler = new WC_Facebook_Product_Feed();
|
3881 |
-
|
3882 |
-
try {
|
3883 |
-
|
3884 |
-
$feed_handler->generate_feed();
|
3885 |
-
|
3886 |
-
} catch ( \Exception $exception ) {
|
3887 |
-
|
3888 |
-
WC_Facebookcommerce_Utils::log( 'Error generating product catalog feed. ' . $exception->getMessage() );
|
3889 |
-
}
|
3890 |
-
}
|
3891 |
-
|
3892 |
-
|
3893 |
/** Deprecated methods ********************************************************************************************/
|
3894 |
|
3895 |
|
101 |
/** @var string the "debug mode" setting ID */
|
102 |
const SETTING_ENABLE_DEBUG_MODE = 'wc_facebook_enable_debug_mode';
|
103 |
|
104 |
+
/** @var string the "debug mode" setting ID */
|
105 |
+
const SETTING_ENABLE_NEW_STYLE_FEED_GENERATOR = 'wc_facebook_enable_new_style_feed_generator';
|
106 |
+
|
107 |
+
/** @var string request headers in the debug log */
|
108 |
+
const SETTING_REQUEST_HEADERS_IN_DEBUG_MODE = 'wc_facebook_request_headers_in_debug_log';
|
109 |
+
|
110 |
/** @var string the standard product description mode name */
|
111 |
const PRODUCT_DESCRIPTION_MODE_STANDARD = 'standard';
|
112 |
|
375 |
|
376 |
add_action( 'before_delete_post', array( $this, 'on_product_delete' ) );
|
377 |
|
378 |
+
add_action( 'add_meta_boxes', 'SkyVerge\WooCommerce\Facebook\Admin\Product_Sync_Meta_Box::register', 10, 1 );
|
379 |
|
380 |
add_action(
|
381 |
'transition_post_status',
|
422 |
// Must be outside of admin for cron to schedule correctly.
|
423 |
add_action( 'sync_all_fb_products_using_feed', array( $this, 'handle_scheduled_resync_action' ), self::FB_PRIORITY_MID );
|
424 |
|
|
|
|
|
|
|
425 |
if ( $this->get_facebook_pixel_id() ) {
|
426 |
$aam_settings = $this->load_aam_settings_of_pixel();
|
427 |
$user_info = WC_Facebookcommerce_Utils::get_user_info( $aam_settings );
|
594 |
wc_deprecated_function( __METHOD__, '1.10.0', '\\SkyVerge\\WooCommerce\\Facebook\\Admin::add_product_list_table_columns_content()' );
|
595 |
}
|
596 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
597 |
/**
|
598 |
* Returns graph API client object.
|
599 |
*
|
613 |
* @param string $product_group_id product group ID
|
614 |
* @return array
|
615 |
*/
|
616 |
+
public function get_variation_product_item_ids( $product, $product_group_id ) {
|
617 |
|
618 |
$product_item_ids_by_variation_id = array();
|
619 |
$missing_product_item_ids = array();
|
1422 |
return;
|
1423 |
}
|
1424 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1425 |
|
1426 |
$product_group_data = array(
|
1427 |
'variants' => $variants,
|
1428 |
);
|
1429 |
|
1430 |
+
// Figure out the matching default variation.
|
1431 |
+
$default_product_fbid = $this->get_product_group_default_variation( $woo_product, $fb_product_group_id );
|
1432 |
+
|
1433 |
if ( $default_product_fbid ) {
|
1434 |
$product_group_data['default_product_id'] = $default_product_fbid;
|
1435 |
}
|
1455 |
|
1456 |
/**
|
1457 |
* Determines if there is a matching variation for the default attributes.
|
1458 |
+
* Select closest matching if best can't be found.
|
1459 |
+
*
|
1460 |
+
* @since 2.6.6
|
1461 |
+
* The algorithm only considers the variations that already have been synchronized to the catalog successfully.
|
1462 |
*
|
1463 |
* @since 2.1.2
|
1464 |
*
|
1465 |
* @param \WC_Facebook_Product $woo_product
|
1466 |
+
* @return integer|null Facebook Catalog variation id.
|
1467 |
*/
|
1468 |
+
private function get_product_group_default_variation( $woo_product, $fb_product_group_id ) {
|
1469 |
|
1470 |
$default_attributes = $woo_product->woo_product->get_default_attributes( 'edit' );
|
1471 |
|
1473 |
return null;
|
1474 |
}
|
1475 |
|
1476 |
+
$default_variation = null;
|
1477 |
+
// Fetch variations that exist in the catalog.
|
1478 |
+
$existing_catalog_variations = $this->find_variation_product_item_ids( $fb_product_group_id );
|
1479 |
+
$existing_catalog_variations_retailer_ids = array_keys( $existing_catalog_variations );
|
1480 |
+
// All woocommerce variations for the product.
|
1481 |
+
$product_variations = $woo_product->woo_product->get_available_variations();
|
1482 |
|
1483 |
+
$best_match_count = 0;
|
1484 |
foreach ( $product_variations as $variation ) {
|
1485 |
|
1486 |
+
$fb_retailer_id = WC_Facebookcommerce_Utils::get_fb_retailer_id(
|
1487 |
+
wc_get_product(
|
1488 |
+
$variation['variation_id']
|
1489 |
+
)
|
1490 |
+
);
|
1491 |
+
|
1492 |
+
// Check if currently processed variation exist in the catalog.
|
1493 |
+
if ( ! in_array( $fb_retailer_id, $existing_catalog_variations_retailer_ids ) ) {
|
1494 |
+
continue;
|
1495 |
+
}
|
1496 |
|
1497 |
+
$variation_attributes = $this->get_product_variation_attributes( $variation );
|
1498 |
+
$variation_attributes_count = count( $variation_attributes );
|
1499 |
+
$matching_attributes_count = count( array_intersect_assoc( $default_attributes, $variation_attributes ) );
|
1500 |
|
1501 |
+
// Check how much current variation matches the selected default attributes.
|
1502 |
+
if ( $matching_attributes_count === $variation_attributes_count ) {
|
1503 |
+
// We found a perfect match;
|
1504 |
+
$default_variation = $existing_catalog_variations[ $fb_retailer_id ];
|
1505 |
break;
|
1506 |
+
} else if ( $matching_attributes_count > $best_match_count ) {
|
1507 |
+
// We found a better match.
|
1508 |
+
$default_variation = $existing_catalog_variations[ $fb_retailer_id ];
|
1509 |
}
|
1510 |
+
|
1511 |
}
|
1512 |
|
1513 |
return $default_variation;
|
3193 |
return (bool) apply_filters( 'wc_facebook_is_debug_mode_enabled', 'yes' === get_option( self::SETTING_ENABLE_DEBUG_MODE ), $this );
|
3194 |
}
|
3195 |
|
3196 |
+
/**
|
3197 |
+
* Determines whether debug mode is enabled.
|
3198 |
+
*
|
3199 |
+
* @since 2.6.6
|
3200 |
+
*
|
3201 |
+
* @return bool
|
3202 |
+
*/
|
3203 |
+
public function is_new_style_feed_generation_enabled() {
|
3204 |
+
return (bool) ( 'yes' === get_option( self::SETTING_ENABLE_NEW_STYLE_FEED_GENERATOR ) );
|
3205 |
+
}
|
3206 |
+
|
3207 |
+
/**
|
3208 |
+
* Check if logging headers is requested.
|
3209 |
+
* For a typical troubleshooting session the request headers bring zero value except making the log unreadable.
|
3210 |
+
* They will be disabled by default. Enabling them will require setting an option in the options table.
|
3211 |
+
*
|
3212 |
+
* @since 2.6.6
|
3213 |
+
*
|
3214 |
+
*/
|
3215 |
+
public function are_headers_requested_for_debug() {
|
3216 |
+
return (bool) get_option( self::SETTING_REQUEST_HEADERS_IN_DEBUG_MODE, false );
|
3217 |
+
}
|
3218 |
+
|
3219 |
|
3220 |
/***
|
3221 |
* Determines if the feed has been migrated from FBE 1 to FBE 1.5
|
3819 |
}
|
3820 |
}
|
3821 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3822 |
/** Deprecated methods ********************************************************************************************/
|
3823 |
|
3824 |
|
facebook-for-woocommerce.php
CHANGED
@@ -11,7 +11,7 @@
|
|
11 |
* Description: Grow your business on Facebook! Use this official plugin to help sell more of your products using Facebook. After completing the setup, you'll be ready to create ads that promote your products and you can also create a shop section on your Page where customers can browse your products on Facebook.
|
12 |
* Author: Facebook
|
13 |
* Author URI: https://www.facebook.com/
|
14 |
-
* Version: 2.6.
|
15 |
* Text Domain: facebook-for-woocommerce
|
16 |
* Tested up to: 5.8
|
17 |
* WC requires at least: 3.5.0
|
@@ -33,7 +33,7 @@ class WC_Facebook_Loader {
|
|
33 |
/**
|
34 |
* @var string the plugin version. This must be in the main plugin file to be automatically bumped by Woorelease.
|
35 |
*/
|
36 |
-
const PLUGIN_VERSION = '2.6.
|
37 |
|
38 |
// Minimum PHP version required by this plugin.
|
39 |
const MINIMUM_PHP_VERSION = '7.0.0';
|
11 |
* Description: Grow your business on Facebook! Use this official plugin to help sell more of your products using Facebook. After completing the setup, you'll be ready to create ads that promote your products and you can also create a shop section on your Page where customers can browse your products on Facebook.
|
12 |
* Author: Facebook
|
13 |
* Author URI: https://www.facebook.com/
|
14 |
+
* Version: 2.6.6
|
15 |
* Text Domain: facebook-for-woocommerce
|
16 |
* Tested up to: 5.8
|
17 |
* WC requires at least: 3.5.0
|
33 |
/**
|
34 |
* @var string the plugin version. This must be in the main plugin file to be automatically bumped by Woorelease.
|
35 |
*/
|
36 |
+
const PLUGIN_VERSION = '2.6.6'; // WRCS: DEFINED_VERSION.
|
37 |
|
38 |
// Minimum PHP version required by this plugin.
|
39 |
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.
|
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"
|
@@ -61,45 +61,45 @@ msgstr ""
|
|
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,49 @@ 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: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:1508
|
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 +157,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 ""
|
@@ -342,6 +322,30 @@ msgstr ""
|
|
342 |
msgid "Map FB Product Set to WC Product Categories"
|
343 |
msgstr ""
|
344 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
345 |
#: includes/Admin/Products.php:101
|
346 |
msgid "Select values for enhanced attributes for this product"
|
347 |
msgstr ""
|
@@ -521,13 +525,27 @@ msgid "Enable debug mode"
|
|
521 |
msgstr ""
|
522 |
|
523 |
#: includes/Admin/Settings_Screens/Connection.php:330
|
524 |
-
msgid "Log plugin events for debugging"
|
525 |
msgstr ""
|
526 |
|
527 |
#: includes/Admin/Settings_Screens/Connection.php:331
|
528 |
msgid "Only enable this if you are experiencing problems with the plugin."
|
529 |
msgstr ""
|
530 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
531 |
#: includes/Admin/Settings_Screens/Messenger.php:122
|
532 |
#. translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag
|
533 |
msgid "%1$sClick here%2$s to manage your Messenger greeting and colors."
|
@@ -990,38 +1008,62 @@ msgstr ""
|
|
990 |
msgid "You do not have permission to finish App Store login."
|
991 |
msgstr ""
|
992 |
|
993 |
-
#: includes/ProductSync/ProductValidator.php:
|
994 |
msgid "Product sync is globally disabled."
|
995 |
msgstr ""
|
996 |
|
997 |
-
#: includes/ProductSync/ProductValidator.php:
|
998 |
msgid "Product is not published."
|
999 |
msgstr ""
|
1000 |
|
1001 |
-
#: includes/ProductSync/ProductValidator.php:
|
1002 |
msgid "Product must be in stock."
|
1003 |
msgstr ""
|
1004 |
|
1005 |
-
#: includes/ProductSync/ProductValidator.php:
|
1006 |
msgid "Product is hidden from catalog and search."
|
1007 |
msgstr ""
|
1008 |
|
1009 |
-
#: includes/ProductSync/ProductValidator.php:
|
1010 |
msgid "Product excluded because of categories."
|
1011 |
msgstr ""
|
1012 |
|
1013 |
-
#: includes/ProductSync/ProductValidator.php:
|
1014 |
msgid "Product excluded because of tags."
|
1015 |
msgstr ""
|
1016 |
|
1017 |
-
#: includes/ProductSync/ProductValidator.php:
|
1018 |
msgid "Sync disabled in product field."
|
1019 |
msgstr ""
|
1020 |
|
1021 |
-
#: includes/ProductSync/ProductValidator.php:
|
1022 |
msgid "If product is not simple, variable or variation it must have a price."
|
1023 |
msgstr ""
|
1024 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1025 |
#: includes/Products/Sync/Background.php:69
|
1026 |
msgid "Job data key \"%s\" not set"
|
1027 |
msgstr ""
|
@@ -1052,19 +1094,19 @@ msgstr ""
|
|
1052 |
msgid "Dismiss"
|
1053 |
msgstr ""
|
1054 |
|
1055 |
-
#: includes/fbproductfeed.php:
|
1056 |
msgid "Could not create product catalog feed directory"
|
1057 |
msgstr ""
|
1058 |
|
1059 |
-
#: includes/fbproductfeed.php:
|
1060 |
msgid "Could not open the product catalog temporary feed file for writing"
|
1061 |
msgstr ""
|
1062 |
|
1063 |
-
#: includes/fbproductfeed.php:
|
1064 |
msgid "Could not open the product catalog feed file for writing"
|
1065 |
msgstr ""
|
1066 |
|
1067 |
-
#: includes/fbproductfeed.php:
|
1068 |
msgid "Could not rename the product catalog feed file"
|
1069 |
msgstr ""
|
1070 |
|
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.6\n"
|
6 |
"Report-Msgid-Bugs-To: "
|
7 |
"https://woocommerce.com/my-account/marketplace-ticket-form/\n"
|
8 |
+
"POT-Creation-Date: 2021-11-03 07:29:59+00:00\n"
|
9 |
"MIME-Version: 1.0\n"
|
10 |
"Content-Type: text/plain; charset=utf-8\n"
|
11 |
"Content-Transfer-Encoding: 8bit\n"
|
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:467
|
65 |
msgid "FB Product Sets"
|
66 |
msgstr ""
|
67 |
|
68 |
+
#: class-wc-facebookcommerce.php:468
|
69 |
msgid "FB Product Set"
|
70 |
msgstr ""
|
71 |
|
72 |
+
#: class-wc-facebookcommerce.php:476
|
73 |
#. translators: Edit item label
|
74 |
msgid "Edit %s"
|
75 |
msgstr ""
|
76 |
|
77 |
+
#: class-wc-facebookcommerce.php:478
|
78 |
#. translators: Add new label
|
79 |
msgid "Add new %s"
|
80 |
msgstr ""
|
81 |
|
82 |
+
#: class-wc-facebookcommerce.php:481
|
83 |
#. translators: No items found text
|
84 |
msgid "No %s found."
|
85 |
msgstr ""
|
86 |
|
87 |
+
#: class-wc-facebookcommerce.php:483
|
88 |
#. translators: Search label
|
89 |
msgid "Search %s."
|
90 |
msgstr ""
|
91 |
|
92 |
+
#: class-wc-facebookcommerce.php:485
|
93 |
#. translators: Text label
|
94 |
msgid "Separate %s with commas"
|
95 |
msgstr ""
|
96 |
|
97 |
+
#: class-wc-facebookcommerce.php:487
|
98 |
#. translators: Text label
|
99 |
msgid "Choose from the most used %s"
|
100 |
msgstr ""
|
101 |
|
102 |
+
#: class-wc-facebookcommerce.php:603
|
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:236
|
111 |
msgid "Facebook Commerce and Dynamic Ads (Pixel) Extension"
|
112 |
msgstr ""
|
113 |
|
114 |
+
#: facebook-commerce.php:1415
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
115 |
msgid "Nothing to update for product group for %1$s"
|
116 |
msgstr ""
|
117 |
|
118 |
+
#: facebook-commerce.php:1828
|
119 |
#. translators: Placeholders %1$s - original error message from Facebook API
|
120 |
msgid "There was an issue connecting to the Facebook API: %1$s"
|
121 |
msgstr ""
|
122 |
|
123 |
+
#: facebook-commerce.php:2164
|
124 |
msgid "Your connection has expired."
|
125 |
msgstr ""
|
126 |
|
127 |
+
#: facebook-commerce.php:2164
|
128 |
msgid ""
|
129 |
"Please click Manage connection > Advanced Options > Update Token to refresh "
|
130 |
"your connection to Facebook."
|
131 |
msgstr ""
|
132 |
|
133 |
+
#: facebook-commerce.php:2171
|
134 |
#. translators: Placeholders %s - error message
|
135 |
msgid "There was an error trying to sync the products to Facebook. %s"
|
136 |
msgstr ""
|
137 |
|
138 |
+
#: facebook-commerce.php:2194 facebook-commerce.php:2367
|
139 |
msgid "Product sync is disabled."
|
140 |
msgstr ""
|
141 |
|
142 |
+
#: facebook-commerce.php:2201 facebook-commerce.php:2374
|
143 |
msgid "The plugin is not configured or the Catalog ID is missing."
|
144 |
msgstr ""
|
145 |
|
146 |
+
#: facebook-commerce.php:2224
|
147 |
msgid ""
|
148 |
"A product sync is in progress. Please wait until the sync finishes before "
|
149 |
"starting a new one."
|
150 |
msgstr ""
|
151 |
|
152 |
+
#: facebook-commerce.php:2236 facebook-commerce.php:2388
|
153 |
msgid ""
|
154 |
"We've detected that your Facebook Product Catalog is no longer valid. This "
|
155 |
"may happen if it was deleted, but could also be a temporary error. If the "
|
157 |
"and setup the plugin again."
|
158 |
msgstr ""
|
159 |
|
160 |
+
#: facebook-commerce.php:2412
|
161 |
msgid "We couldn't create the feed or upload the product information."
|
162 |
msgstr ""
|
163 |
|
164 |
+
#: facebook-commerce.php:2880
|
165 |
msgid "Hi! We're here to answer any questions you may have."
|
166 |
msgstr ""
|
167 |
|
168 |
+
#: facebook-commerce.php:3270
|
169 |
msgid "Facebook for WooCommerce error:"
|
170 |
msgstr ""
|
171 |
|
172 |
+
#: facebook-commerce.php:3352
|
173 |
msgid ""
|
174 |
"There was an error trying to retrieve information about the Facebook page: "
|
175 |
"%s"
|
176 |
msgstr ""
|
177 |
|
178 |
+
#: facebook-commerce.php:3403
|
179 |
msgid "Get started with Messenger Customer Chat"
|
180 |
msgstr ""
|
181 |
|
182 |
+
#: facebook-commerce.php:3404
|
183 |
msgid "Get started with Instagram Shopping"
|
184 |
msgstr ""
|
185 |
|
186 |
+
#: facebook-commerce.php:3639
|
187 |
#. translators: Placeholders %1$s - original error message from Facebook API
|
188 |
msgid "There was an issue connecting to the Facebook API: %s"
|
189 |
msgstr ""
|
322 |
msgid "Map FB Product Set to WC Product Categories"
|
323 |
msgstr ""
|
324 |
|
325 |
+
#: includes/Admin/Product_Sync_Meta_Box.php:37
|
326 |
+
msgid "Facebook Product Sync"
|
327 |
+
msgstr ""
|
328 |
+
|
329 |
+
#: includes/Admin/Product_Sync_Meta_Box.php:78
|
330 |
+
msgid "Facebook ID:"
|
331 |
+
msgstr ""
|
332 |
+
|
333 |
+
#: includes/Admin/Product_Sync_Meta_Box.php:89
|
334 |
+
msgid "Variant IDs:"
|
335 |
+
msgstr ""
|
336 |
+
|
337 |
+
#: includes/Admin/Product_Sync_Meta_Box.php:121
|
338 |
+
msgid "Reset Facebook metadata"
|
339 |
+
msgstr ""
|
340 |
+
|
341 |
+
#: includes/Admin/Product_Sync_Meta_Box.php:126
|
342 |
+
msgid "Delete product(s) on Facebook"
|
343 |
+
msgstr ""
|
344 |
+
|
345 |
+
#: includes/Admin/Product_Sync_Meta_Box.php:138
|
346 |
+
msgid "This product is not yet synced to Facebook."
|
347 |
+
msgstr ""
|
348 |
+
|
349 |
#: includes/Admin/Products.php:101
|
350 |
msgid "Select values for enhanced attributes for this product"
|
351 |
msgstr ""
|
525 |
msgstr ""
|
526 |
|
527 |
#: includes/Admin/Settings_Screens/Connection.php:330
|
528 |
+
msgid "Log plugin events for debugging."
|
529 |
msgstr ""
|
530 |
|
531 |
#: includes/Admin/Settings_Screens/Connection.php:331
|
532 |
msgid "Only enable this if you are experiencing problems with the plugin."
|
533 |
msgstr ""
|
534 |
|
535 |
+
#: includes/Admin/Settings_Screens/Connection.php:337
|
536 |
+
msgid "Experimental! Enable new style feed generation"
|
537 |
+
msgstr ""
|
538 |
+
|
539 |
+
#: includes/Admin/Settings_Screens/Connection.php:339
|
540 |
+
msgid "Use new, memory improved, feed generation process."
|
541 |
+
msgstr ""
|
542 |
+
|
543 |
+
#: includes/Admin/Settings_Screens/Connection.php:340
|
544 |
+
msgid ""
|
545 |
+
"Experimental feature. Only enable this if you are experiencing problems "
|
546 |
+
"with feed generation. This is an experimental feature in testing phase."
|
547 |
+
msgstr ""
|
548 |
+
|
549 |
#: includes/Admin/Settings_Screens/Messenger.php:122
|
550 |
#. translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag
|
551 |
msgid "%1$sClick here%2$s to manage your Messenger greeting and colors."
|
1008 |
msgid "You do not have permission to finish App Store login."
|
1009 |
msgstr ""
|
1010 |
|
1011 |
+
#: includes/ProductSync/ProductValidator.php:185
|
1012 |
msgid "Product sync is globally disabled."
|
1013 |
msgstr ""
|
1014 |
|
1015 |
+
#: includes/ProductSync/ProductValidator.php:198
|
1016 |
msgid "Product is not published."
|
1017 |
msgstr ""
|
1018 |
|
1019 |
+
#: includes/ProductSync/ProductValidator.php:209
|
1020 |
msgid "Product must be in stock."
|
1021 |
msgstr ""
|
1022 |
|
1023 |
+
#: includes/ProductSync/ProductValidator.php:224
|
1024 |
msgid "Product is hidden from catalog and search."
|
1025 |
msgstr ""
|
1026 |
|
1027 |
+
#: includes/ProductSync/ProductValidator.php:239
|
1028 |
msgid "Product excluded because of categories."
|
1029 |
msgstr ""
|
1030 |
|
1031 |
+
#: includes/ProductSync/ProductValidator.php:246
|
1032 |
msgid "Product excluded because of tags."
|
1033 |
msgstr ""
|
1034 |
|
1035 |
+
#: includes/ProductSync/ProductValidator.php:257
|
1036 |
msgid "Sync disabled in product field."
|
1037 |
msgstr ""
|
1038 |
|
1039 |
+
#: includes/ProductSync/ProductValidator.php:292
|
1040 |
msgid "If product is not simple, variable or variation it must have a price."
|
1041 |
msgstr ""
|
1042 |
|
1043 |
+
#: includes/ProductSync/ProductValidator.php:318
|
1044 |
+
msgid ""
|
1045 |
+
"Product description is all capital letters. Please change the description "
|
1046 |
+
"to sentence case in order to allow synchronization of your product."
|
1047 |
+
msgstr ""
|
1048 |
+
|
1049 |
+
#: includes/ProductSync/ProductValidator.php:321
|
1050 |
+
msgid "Product description is too long. Maximum allowed length is 5000 characters."
|
1051 |
+
msgstr ""
|
1052 |
+
|
1053 |
+
#: includes/ProductSync/ProductValidator.php:340
|
1054 |
+
msgid ""
|
1055 |
+
"Product title is all capital letters. Please change the title to sentence "
|
1056 |
+
"case in order to allow synchronization of your product."
|
1057 |
+
msgstr ""
|
1058 |
+
|
1059 |
+
#: includes/ProductSync/ProductValidator.php:343
|
1060 |
+
msgid "Product title is too long. Maximum allowed length is 150 characters."
|
1061 |
+
msgstr ""
|
1062 |
+
|
1063 |
+
#: includes/ProductSync/ProductValidator.php:367
|
1064 |
+
msgid "Too many attributes selected for product. Use 4 or less."
|
1065 |
+
msgstr ""
|
1066 |
+
|
1067 |
#: includes/Products/Sync/Background.php:69
|
1068 |
msgid "Job data key \"%s\" not set"
|
1069 |
msgstr ""
|
1094 |
msgid "Dismiss"
|
1095 |
msgstr ""
|
1096 |
|
1097 |
+
#: includes/fbproductfeed.php:278
|
1098 |
msgid "Could not create product catalog feed directory"
|
1099 |
msgstr ""
|
1100 |
|
1101 |
+
#: includes/fbproductfeed.php:382
|
1102 |
msgid "Could not open the product catalog temporary feed file for writing"
|
1103 |
msgstr ""
|
1104 |
|
1105 |
+
#: includes/fbproductfeed.php:389
|
1106 |
msgid "Could not open the product catalog feed file for writing"
|
1107 |
msgstr ""
|
1108 |
|
1109 |
+
#: includes/fbproductfeed.php:453
|
1110 |
msgid "Could not rename the product catalog feed file"
|
1111 |
msgstr ""
|
1112 |
|
includes/Admin/Product_Sync_Meta_Box.php
ADDED
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace SkyVerge\WooCommerce\Facebook\Admin;
|
4 |
+
|
5 |
+
defined( 'ABSPATH' ) || exit;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Class responsible for display and operations of product sync status metabox.
|
9 |
+
*
|
10 |
+
* @since 2.6.6
|
11 |
+
*/
|
12 |
+
class Product_Sync_Meta_Box {
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Register metabox assets and add the metabox.
|
16 |
+
*/
|
17 |
+
public static function register() {
|
18 |
+
$ajax_data = array(
|
19 |
+
'nonce' => wp_create_nonce( 'wc_facebook_metabox_jsx' ),
|
20 |
+
);
|
21 |
+
|
22 |
+
wp_enqueue_script(
|
23 |
+
'wc_facebook_metabox_jsx',
|
24 |
+
facebook_for_woocommerce()->get_asset_build_dir_url() . '/admin/metabox.js',
|
25 |
+
array(),
|
26 |
+
\WC_Facebookcommerce::PLUGIN_VERSION
|
27 |
+
);
|
28 |
+
|
29 |
+
wp_localize_script(
|
30 |
+
'wc_facebook_metabox_jsx',
|
31 |
+
'wc_facebook_metabox_jsx',
|
32 |
+
$ajax_data
|
33 |
+
);
|
34 |
+
|
35 |
+
add_meta_box(
|
36 |
+
'facebook_metabox',
|
37 |
+
__( 'Facebook Product Sync', 'facebook-for-woocommerce' ),
|
38 |
+
__CLASS__ . '::output',
|
39 |
+
'product',
|
40 |
+
'side'
|
41 |
+
);
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Renders the content of the product meta box.
|
46 |
+
*
|
47 |
+
* @since 2.6.6
|
48 |
+
*/
|
49 |
+
public static function output() {
|
50 |
+
global $post;
|
51 |
+
|
52 |
+
$fb_integration = facebook_for_woocommerce()->get_integration();
|
53 |
+
$fb_product = new \WC_Facebook_Product( $post->ID );
|
54 |
+
$fb_product_group_id = null;
|
55 |
+
$should_sync = true;
|
56 |
+
$no_sync_reason = '';
|
57 |
+
|
58 |
+
if ( $fb_product->woo_product instanceof \WC_Product ) {
|
59 |
+
try {
|
60 |
+
facebook_for_woocommerce()->get_product_sync_validator( $fb_product->woo_product )->validate();
|
61 |
+
} catch ( \Exception $e ) {
|
62 |
+
$should_sync = false;
|
63 |
+
$no_sync_reason = $e->getMessage();
|
64 |
+
}
|
65 |
+
}
|
66 |
+
|
67 |
+
if ( $should_sync || $fb_product->woo_product->is_type( 'variable' ) ) {
|
68 |
+
$fb_product_group_id = $fb_integration->get_product_fbid( $fb_integration::FB_PRODUCT_GROUP_ID, $post->ID, $fb_product->woo_product );
|
69 |
+
}
|
70 |
+
?>
|
71 |
+
<span id="fb_metadata">
|
72 |
+
<?php
|
73 |
+
|
74 |
+
if ( $fb_product_group_id ) {
|
75 |
+
|
76 |
+
?>
|
77 |
+
|
78 |
+
<?php echo esc_html__( 'Facebook ID:', 'facebook-for-woocommerce' ); ?>
|
79 |
+
<a href="https://facebook.com/<?php echo esc_attr( $fb_product_group_id ); ?>" target="_blank"><?php echo esc_html( $fb_product_group_id ); ?></a>
|
80 |
+
|
81 |
+
<?php if ( \WC_Facebookcommerce_Utils::is_variable_type( $fb_product->get_type() ) ) : ?>
|
82 |
+
|
83 |
+
<?php
|
84 |
+
$product_item_ids_by_variation_id = $fb_integration->get_variation_product_item_ids( $fb_product, $fb_product_group_id );
|
85 |
+
if ( $product_item_ids_by_variation_id ) :
|
86 |
+
?>
|
87 |
+
|
88 |
+
<p>
|
89 |
+
<?php echo esc_html__( 'Variant IDs:', 'facebook-for-woocommerce' ); ?><br/>
|
90 |
+
|
91 |
+
<?php
|
92 |
+
foreach ( $product_item_ids_by_variation_id as $variation_id => $product_item_id ) :
|
93 |
+
$variation = wc_get_product( $variation_id );
|
94 |
+
$show_link = true;
|
95 |
+
|
96 |
+
try {
|
97 |
+
facebook_for_woocommerce()->get_product_sync_validator( $variation )->validate();
|
98 |
+
} catch ( \Exception $e ) {
|
99 |
+
$info = $e->getMessage();
|
100 |
+
$show_link = false;
|
101 |
+
}
|
102 |
+
?>
|
103 |
+
<?php echo esc_html( $variation_id ); ?>:
|
104 |
+
<?php if ( $show_link ) : ?>
|
105 |
+
<a href="https://facebook.com/<?php echo esc_attr( $product_item_id ); ?>" target="_blank"><?php echo esc_html( $product_item_id ); ?></a>
|
106 |
+
<?php else : ?>
|
107 |
+
<?php echo esc_html( $info ); ?>
|
108 |
+
<?php endif; ?>
|
109 |
+
<br/>
|
110 |
+
<?php endforeach; ?>
|
111 |
+
</p>
|
112 |
+
|
113 |
+
<?php endif; ?>
|
114 |
+
|
115 |
+
<?php endif; ?>
|
116 |
+
|
117 |
+
<input name="is_product_page" type="hidden" value="1"/>
|
118 |
+
|
119 |
+
<p/>
|
120 |
+
<a href="#" onclick="fb_reset_product( <?php echo esc_js( $post->ID ); ?> )">
|
121 |
+
<?php echo esc_html__( 'Reset Facebook metadata', 'facebook-for-woocommerce' ); ?>
|
122 |
+
</a>
|
123 |
+
|
124 |
+
<p/>
|
125 |
+
<a href="#" onclick="fb_delete_product( <?php echo esc_js( $post->ID ); ?> )">
|
126 |
+
<?php echo esc_html__( 'Delete product(s) on Facebook', 'facebook-for-woocommerce' ); ?>
|
127 |
+
</a>
|
128 |
+
|
129 |
+
<?php
|
130 |
+
|
131 |
+
} elseif ( ! $should_sync ) {
|
132 |
+
?>
|
133 |
+
<b><?php echo esc_html( $no_sync_reason ); ?></b>
|
134 |
+
<?php
|
135 |
+
} else {
|
136 |
+
|
137 |
+
?>
|
138 |
+
<b><?php echo esc_html__( 'This product is not yet synced to Facebook.', 'facebook-for-woocommerce' ); ?></b>
|
139 |
+
<?php
|
140 |
+
}
|
141 |
+
|
142 |
+
?>
|
143 |
+
</span>
|
144 |
+
<?php
|
145 |
+
}
|
146 |
+
}
|
includes/Admin/Settings_Screens/Connection.php
CHANGED
@@ -327,11 +327,20 @@ class Connection extends Admin\Abstract_Settings_Screen {
|
|
327 |
'id' => \WC_Facebookcommerce_Integration::SETTING_ENABLE_DEBUG_MODE,
|
328 |
'title' => __( 'Enable debug mode', 'facebook-for-woocommerce' ),
|
329 |
'type' => 'checkbox',
|
330 |
-
'desc' => __( 'Log plugin events for debugging', 'facebook-for-woocommerce' ),
|
331 |
'desc_tip' => __( 'Only enable this if you are experiencing problems with the plugin.', 'facebook-for-woocommerce' ),
|
332 |
'default' => 'no',
|
333 |
),
|
334 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
335 |
array( 'type' => 'sectionend' ),
|
336 |
|
337 |
);
|
327 |
'id' => \WC_Facebookcommerce_Integration::SETTING_ENABLE_DEBUG_MODE,
|
328 |
'title' => __( 'Enable debug mode', 'facebook-for-woocommerce' ),
|
329 |
'type' => 'checkbox',
|
330 |
+
'desc' => __( 'Log plugin events for debugging.', 'facebook-for-woocommerce' ),
|
331 |
'desc_tip' => __( 'Only enable this if you are experiencing problems with the plugin.', 'facebook-for-woocommerce' ),
|
332 |
'default' => 'no',
|
333 |
),
|
334 |
|
335 |
+
array(
|
336 |
+
'id' => \WC_Facebookcommerce_Integration::SETTING_ENABLE_NEW_STYLE_FEED_GENERATOR,
|
337 |
+
'title' => __( 'Experimental! Enable new style feed generation', 'facebook-for-woocommerce' ),
|
338 |
+
'type' => 'checkbox',
|
339 |
+
'desc' => __( 'Use new, memory improved, feed generation process.', 'facebook-for-woocommerce' ),
|
340 |
+
'desc_tip' => __( 'Experimental feature. Only enable this if you are experiencing problems with feed generation. This is an experimental feature in testing phase.', 'facebook-for-woocommerce' ),
|
341 |
+
'default' => 'no',
|
342 |
+
),
|
343 |
+
|
344 |
array( 'type' => 'sectionend' ),
|
345 |
|
346 |
);
|
includes/Jobs/GenerateProductFeed.php
CHANGED
@@ -23,14 +23,19 @@ class GenerateProductFeed extends AbstractChainedJob {
|
|
23 |
* Called before starting the job.
|
24 |
*/
|
25 |
protected function handle_start() {
|
26 |
-
|
|
|
|
|
|
|
27 |
}
|
28 |
|
29 |
/**
|
30 |
* Called after the finishing the job.
|
31 |
*/
|
32 |
protected function handle_end() {
|
33 |
-
|
|
|
|
|
34 |
}
|
35 |
|
36 |
/**
|
@@ -50,8 +55,8 @@ class GenerateProductFeed extends AbstractChainedJob {
|
|
50 |
$product_ids = $wpdb->get_col(
|
51 |
$wpdb->prepare(
|
52 |
"SELECT post.ID
|
53 |
-
FROM
|
54 |
-
LEFT JOIN
|
55 |
WHERE
|
56 |
( post.post_type = 'product_variation' AND parent.post_status = 'publish' )
|
57 |
OR
|
@@ -66,55 +71,47 @@ class GenerateProductFeed extends AbstractChainedJob {
|
|
66 |
return array_map( 'intval', $product_ids );
|
67 |
}
|
68 |
|
69 |
-
|
70 |
-
*
|
71 |
*
|
72 |
-
*
|
73 |
*
|
74 |
-
* @param array $items
|
|
|
75 |
*
|
76 |
-
* @
|
77 |
*/
|
78 |
-
protected function
|
79 |
-
//
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
|
|
|
|
|
|
|
|
86 |
'include' => $items,
|
87 |
'orderby' => 'none',
|
88 |
-
|
|
|
89 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
}
|
91 |
|
92 |
/**
|
93 |
-
*
|
94 |
-
*
|
95 |
-
* @param WC_Product $product A single item from the get_items_for_batch() method.
|
96 |
-
* @param array $args The args for the job.
|
97 |
-
*
|
98 |
-
* @throws Exception On error. The failure will be logged by Action Scheduler and the job chain will stop.
|
99 |
*/
|
100 |
-
protected function process_item( $product,
|
101 |
-
try {
|
102 |
-
if ( ! $product ) {
|
103 |
-
throw new Exception( 'Product not found.' );
|
104 |
-
}
|
105 |
-
|
106 |
-
$this->log( $product->get_id() );
|
107 |
-
|
108 |
-
} catch ( Exception $e ) {
|
109 |
-
$this->log(
|
110 |
-
sprintf(
|
111 |
-
'Error processing item #%d - %s',
|
112 |
-
$product instanceof WC_Product ? $product->get_id() : 0,
|
113 |
-
$e->getMessage()
|
114 |
-
)
|
115 |
-
);
|
116 |
-
}
|
117 |
-
}
|
118 |
|
119 |
/**
|
120 |
* Get the name/slug of the job.
|
23 |
* Called before starting the job.
|
24 |
*/
|
25 |
protected function handle_start() {
|
26 |
+
$feed_handler = new \WC_Facebook_Product_Feed();
|
27 |
+
$feed_handler->create_files_to_protect_product_feed_directory();
|
28 |
+
$feed_handler->prepare_temporary_feed_file();
|
29 |
+
facebook_for_woocommerce()->get_tracker()->reset_batch_generation_time();
|
30 |
}
|
31 |
|
32 |
/**
|
33 |
* Called after the finishing the job.
|
34 |
*/
|
35 |
protected function handle_end() {
|
36 |
+
$feed_handler = new \WC_Facebook_Product_Feed();
|
37 |
+
$feed_handler->rename_temporary_feed_file_to_final_feed_file();
|
38 |
+
facebook_for_woocommerce()->get_tracker()->save_batch_generation_time();
|
39 |
}
|
40 |
|
41 |
/**
|
55 |
$product_ids = $wpdb->get_col(
|
56 |
$wpdb->prepare(
|
57 |
"SELECT post.ID
|
58 |
+
FROM {$wpdb->posts} as post
|
59 |
+
LEFT JOIN {$wpdb->posts} as parent ON post.post_parent = parent.ID
|
60 |
WHERE
|
61 |
( post.post_type = 'product_variation' AND parent.post_status = 'publish' )
|
62 |
OR
|
71 |
return array_map( 'intval', $product_ids );
|
72 |
}
|
73 |
|
74 |
+
/**
|
75 |
+
* Processes a batch of items.
|
76 |
*
|
77 |
+
* @since 1.1.0
|
78 |
*
|
79 |
+
* @param array $items The items of the current batch.
|
80 |
+
* @param array $args The args for the job.
|
81 |
*
|
82 |
+
* @throws Exception On error. The failure will be logged by Action Scheduler and the job chain will stop.
|
83 |
*/
|
84 |
+
protected function process_items( array $items, array $args ) {
|
85 |
+
// Grab start time.
|
86 |
+
$start_time = microtime( true );
|
87 |
+
/*
|
88 |
+
* Pre-fetch full product objects.
|
89 |
+
* Variable products will be filtered out here since we don't need them for the feed. It's important to not
|
90 |
+
* filter out variable products in ::get_items_for_batch() because if a batch only contains variable products
|
91 |
+
* the job will end prematurely thinking it has nothing more to process.
|
92 |
+
*/
|
93 |
+
$products = wc_get_products(
|
94 |
+
array(
|
95 |
+
'type' => array( 'simple', 'variation' ),
|
96 |
'include' => $items,
|
97 |
'orderby' => 'none',
|
98 |
+
'limit' => $this->get_batch_size(),
|
99 |
+
)
|
100 |
);
|
101 |
+
$feed_handler = new \WC_Facebook_Product_Feed();
|
102 |
+
$temp_feed_file = fopen( $feed_handler->get_temp_file_path(), 'a' );
|
103 |
+
$feed_handler->write_products_feed_to_temp_file( $products, $temp_feed_file );
|
104 |
+
if ( is_resource( $temp_feed_file ) ) {
|
105 |
+
fclose( $temp_feed_file );
|
106 |
+
}
|
107 |
+
facebook_for_woocommerce()->get_tracker()->increment_batch_generation_time( microtime( true ) - $start_time );
|
108 |
}
|
109 |
|
110 |
/**
|
111 |
+
* Empty function to satisfy parent class requirements.
|
112 |
+
* We don't use it because we are processing the whole batch at once in process_items.
|
|
|
|
|
|
|
|
|
113 |
*/
|
114 |
+
protected function process_item( $product, $args ) {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
115 |
|
116 |
/**
|
117 |
* Get the name/slug of the job.
|
includes/ProductSync/ProductInvalidException.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace SkyVerge\WooCommerce\Facebook\ProductSync;
|
4 |
+
|
5 |
+
use Exception;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Class ProductInvalidException
|
9 |
+
*
|
10 |
+
* Exception for when a product configuration is not correct in terms of Facebook product sync.
|
11 |
+
* There are limitations that will exclude product from Facebook catalog. We want to inform
|
12 |
+
* user as early as possible.
|
13 |
+
*/
|
14 |
+
class ProductInvalidException extends Exception {}
|
includes/ProductSync/ProductValidator.php
CHANGED
@@ -3,9 +3,14 @@
|
|
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 |
*
|
@@ -22,6 +27,27 @@ class ProductValidator {
|
|
22 |
*/
|
23 |
const SYNC_ENABLED_META_KEY = '_wc_facebook_sync_enabled';
|
24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
/**
|
26 |
* The FB integration instance.
|
27 |
*
|
@@ -50,7 +76,8 @@ class ProductValidator {
|
|
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
|
|
|
54 |
|
55 |
if ( $product->get_parent_id() ) {
|
56 |
$parent_product = wc_get_product( $product->get_parent_id() );
|
@@ -75,6 +102,8 @@ class ProductValidator {
|
|
75 |
$this->validate_product_price();
|
76 |
$this->validate_product_visibility();
|
77 |
$this->validate_product_terms();
|
|
|
|
|
78 |
}
|
79 |
|
80 |
/**
|
@@ -91,6 +120,8 @@ class ProductValidator {
|
|
91 |
$this->validate_product_price();
|
92 |
$this->validate_product_visibility();
|
93 |
$this->validate_product_terms();
|
|
|
|
|
94 |
}
|
95 |
|
96 |
/**
|
@@ -103,6 +134,8 @@ class ProductValidator {
|
|
103 |
$this->validate();
|
104 |
} catch ( ProductExcludedException $e ) {
|
105 |
return false;
|
|
|
|
|
106 |
}
|
107 |
|
108 |
return true;
|
@@ -118,6 +151,8 @@ class ProductValidator {
|
|
118 |
$this->validate_product_terms();
|
119 |
} catch ( ProductExcludedException $e ) {
|
120 |
return false;
|
|
|
|
|
121 |
}
|
122 |
|
123 |
return true;
|
@@ -133,6 +168,8 @@ class ProductValidator {
|
|
133 |
$this->validate_product_sync_field();
|
134 |
} catch ( ProductExcludedException $e ) {
|
135 |
return false;
|
|
|
|
|
136 |
}
|
137 |
|
138 |
return true;
|
@@ -256,4 +293,79 @@ class ProductValidator {
|
|
256 |
}
|
257 |
}
|
258 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
259 |
}
|
3 |
namespace SkyVerge\WooCommerce\Facebook\ProductSync;
|
4 |
|
5 |
use SkyVerge\WooCommerce\Facebook\Products;
|
6 |
+
use WC_Facebook_Product;
|
7 |
use WC_Product;
|
8 |
use WC_Facebookcommerce_Integration;
|
9 |
|
10 |
+
if ( ! class_exists( 'WC_Facebookcommerce_Utils' ) ) {
|
11 |
+
include_once '../fbutils.php';
|
12 |
+
}
|
13 |
+
|
14 |
/**
|
15 |
* Class ProductValidator
|
16 |
*
|
27 |
*/
|
28 |
const SYNC_ENABLED_META_KEY = '_wc_facebook_sync_enabled';
|
29 |
|
30 |
+
/**
|
31 |
+
* Maximum length of product description.
|
32 |
+
*
|
33 |
+
* @var int
|
34 |
+
*/
|
35 |
+
const MAX_DESCRIPTION_LENGTH = 5000;
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Maximum length of product title.
|
39 |
+
*
|
40 |
+
* @var int
|
41 |
+
*/
|
42 |
+
const MAX_TITLE_LENGTH = 150;
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Maximum allowed attributes in a variation;
|
46 |
+
*
|
47 |
+
* @var int
|
48 |
+
*/
|
49 |
+
const MAX_NUMBER_OF_ATTRIBUTES_IN_VARIATION = 4;
|
50 |
+
|
51 |
/**
|
52 |
* The FB integration instance.
|
53 |
*
|
76 |
* @param WC_Product $product The product to validate. Accepts both variations and variable products.
|
77 |
*/
|
78 |
public function __construct( WC_Facebookcommerce_Integration $integration, WC_Product $product ) {
|
79 |
+
$this->product = $product;
|
80 |
+
$this->facebook_product = new WC_Facebook_Product( $product->get_id() );
|
81 |
|
82 |
if ( $product->get_parent_id() ) {
|
83 |
$parent_product = wc_get_product( $product->get_parent_id() );
|
102 |
$this->validate_product_price();
|
103 |
$this->validate_product_visibility();
|
104 |
$this->validate_product_terms();
|
105 |
+
$this->validate_product_description();
|
106 |
+
$this->validate_product_title();
|
107 |
}
|
108 |
|
109 |
/**
|
120 |
$this->validate_product_price();
|
121 |
$this->validate_product_visibility();
|
122 |
$this->validate_product_terms();
|
123 |
+
$this->validate_product_description();
|
124 |
+
$this->validate_product_title();
|
125 |
}
|
126 |
|
127 |
/**
|
134 |
$this->validate();
|
135 |
} catch ( ProductExcludedException $e ) {
|
136 |
return false;
|
137 |
+
} catch ( ProductInvalidException $e ) {
|
138 |
+
return false;
|
139 |
}
|
140 |
|
141 |
return true;
|
151 |
$this->validate_product_terms();
|
152 |
} catch ( ProductExcludedException $e ) {
|
153 |
return false;
|
154 |
+
} catch ( ProductInvalidException $e ) {
|
155 |
+
return false;
|
156 |
}
|
157 |
|
158 |
return true;
|
168 |
$this->validate_product_sync_field();
|
169 |
} catch ( ProductExcludedException $e ) {
|
170 |
return false;
|
171 |
+
} catch ( ProductInvalidException $e ) {
|
172 |
+
return false;
|
173 |
}
|
174 |
|
175 |
return true;
|
293 |
}
|
294 |
}
|
295 |
|
296 |
+
/**
|
297 |
+
* Check if the description field has correct format according to:
|
298 |
+
* Product Description Specifications for Catalogs : https://www.facebook.com/business/help/2302017289821154
|
299 |
+
*
|
300 |
+
* @throws ProductInvalidException If product description does not meet the requirements.
|
301 |
+
*/
|
302 |
+
protected function validate_product_description() {
|
303 |
+
/*
|
304 |
+
* First step is to select the description that we want to evaluate.
|
305 |
+
* Main description is the one provided for the product in the Facebook.
|
306 |
+
* If it is blank, product description will be used.
|
307 |
+
* If product description is blank, shortname will be used.
|
308 |
+
*/
|
309 |
+
$description = $this->facebook_product->get_fb_description();
|
310 |
+
|
311 |
+
/*
|
312 |
+
* Requirements:
|
313 |
+
* - No all caps descriptions.
|
314 |
+
* - Max length 5000.
|
315 |
+
* - Min length 30 ( tested and not required, will not enforce until this will become a hard requirement )
|
316 |
+
*/
|
317 |
+
if ( \WC_Facebookcommerce_Utils::is_all_caps( $description ) ) {
|
318 |
+
throw new ProductInvalidException( __( 'Product description is all capital letters. Please change the description to sentence case in order to allow synchronization of your product.', 'facebook-for-woocommerce' ) );
|
319 |
+
}
|
320 |
+
if ( strlen( $description ) > self::MAX_DESCRIPTION_LENGTH ) {
|
321 |
+
throw new ProductInvalidException( __( 'Product description is too long. Maximum allowed length is 5000 characters.', 'facebook-for-woocommerce' ) );
|
322 |
+
}
|
323 |
+
}
|
324 |
+
|
325 |
+
/**
|
326 |
+
* Check if the title field has correct format according to:
|
327 |
+
* Product Title Specifications for Catalogs : https://www.facebook.com/business/help/2104231189874655
|
328 |
+
*
|
329 |
+
* @throws ProductInvalidException If product title does not meet the requirements.
|
330 |
+
*/
|
331 |
+
protected function validate_product_title() {
|
332 |
+
$title = $this->product->get_title();
|
333 |
+
|
334 |
+
/*
|
335 |
+
* Requirements:
|
336 |
+
* - No all caps title.
|
337 |
+
* - Max length 150.
|
338 |
+
*/
|
339 |
+
if ( \WC_Facebookcommerce_Utils::is_all_caps( $title ) ) {
|
340 |
+
throw new ProductInvalidException( __( 'Product title is all capital letters. Please change the title to sentence case in order to allow synchronization of your product.', 'facebook-for-woocommerce' ) );
|
341 |
+
}
|
342 |
+
if ( strlen( $title ) > self::MAX_TITLE_LENGTH ) {
|
343 |
+
throw new ProductInvalidException( __( 'Product title is too long. Maximum allowed length is 150 characters.', 'facebook-for-woocommerce' ) );
|
344 |
+
}
|
345 |
+
}
|
346 |
+
|
347 |
+
/**
|
348 |
+
* Check if variation product has proper settings.
|
349 |
+
*
|
350 |
+
* @throws ProductInvalidException If product variation violates some requirements.
|
351 |
+
*/
|
352 |
+
protected function validate_variation_structure() {
|
353 |
+
// Check if we are dealing with a variation.
|
354 |
+
if ( ! $this->product->is_type( 'variation' ) ) {
|
355 |
+
return;
|
356 |
+
}
|
357 |
+
$attributes = $this->product->get_attributes();
|
358 |
+
|
359 |
+
$used_attributes_count = count(
|
360 |
+
array_filter(
|
361 |
+
$attributes
|
362 |
+
)
|
363 |
+
);
|
364 |
+
|
365 |
+
// No more than MAX_NUMBER_OF_ATTRIBUTES_IN_VARIATION ar allowed to be used.
|
366 |
+
if ( $used_attributes_count > self::MAX_NUMBER_OF_ATTRIBUTES_IN_VARIATION ) {
|
367 |
+
throw new ProductInvalidException( __( 'Too many attributes selected for product. Use 4 or less.', 'facebook-for-woocommerce' ) );
|
368 |
+
}
|
369 |
+
}
|
370 |
+
|
371 |
}
|
includes/Products/Feed.php
CHANGED
@@ -143,15 +143,19 @@ class Feed {
|
|
143 |
* @internal
|
144 |
*
|
145 |
* @since 1.11.0
|
|
|
146 |
*/
|
147 |
public function regenerate_feed() {
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
|
|
|
|
|
|
|
|
152 |
}
|
153 |
|
154 |
-
|
155 |
/**
|
156 |
* Schedules the recurring feed generation.
|
157 |
*
|
143 |
* @internal
|
144 |
*
|
145 |
* @since 1.11.0
|
146 |
+
* @since 2.6.6 Enable new feed generation code if requested.
|
147 |
*/
|
148 |
public function regenerate_feed() {
|
149 |
+
// Maybe use new ( experimental ), feed generation framework.
|
150 |
+
if ( facebook_for_woocommerce()->get_integration()->is_new_style_feed_generation_enabled() ) {
|
151 |
+
$generate_feed_job = facebook_for_woocommerce()->job_registry->generate_product_feed_job;
|
152 |
+
$generate_feed_job->queue_start();
|
153 |
+
} else {
|
154 |
+
$feed_handler = new \WC_Facebook_Product_Feed();
|
155 |
+
$feed_handler->generate_feed();
|
156 |
+
}
|
157 |
}
|
158 |
|
|
|
159 |
/**
|
160 |
* Schedules the recurring feed generation.
|
161 |
*
|
includes/Utilities/Tracker.php
CHANGED
@@ -29,12 +29,33 @@ class Tracker {
|
|
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
|
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 |
*
|
@@ -103,13 +124,27 @@ class Tracker {
|
|
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 |
*
|
@@ -136,6 +171,13 @@ class Tracker {
|
|
136 |
*/
|
137 |
$data['extensions']['facebook-for-woocommerce']['product-feed-config'] = get_transient( self::TRANSIENT_WCTRACKER_FB_FEED_CONFIG );
|
138 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
139 |
return $data;
|
140 |
}
|
141 |
|
@@ -151,6 +193,58 @@ class Tracker {
|
|
151 |
set_transient( self::TRANSIENT_WCTRACKER_FEED_GENERATION_TIME, $time_in_seconds, self::TRANSIENT_WCTRACKER_LIFE_TIME );
|
152 |
}
|
153 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
154 |
/**
|
155 |
* Store the fact that the feed has been requested by Facebook in a transient.
|
156 |
* This will later be added to next tracker snapshot.
|
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 minus one 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; how long it took to generate already generated batches.
|
40 |
+
*
|
41 |
+
* @var string
|
42 |
+
*/
|
43 |
+
const TRANSIENT_WCTRACKER_FEED_GENERATION_BATCH_TIME = 'facebook_for_woocommerce_wctracker_feed_generation_batch_time';
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Transient key name; how much wall ( clock ) time it took to generate the feed file.
|
47 |
+
*
|
48 |
+
* @var string
|
49 |
+
*/
|
50 |
+
const TRANSIENT_WCTRACKER_FEED_GENERATION_BATCH_WALL_TIME = 'facebook_for_woocommerce_wctracker_feed_generation_batch_wall_time';
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Transient key name; the time when was the batched feed generation started.
|
54 |
+
*
|
55 |
+
* @var string
|
56 |
+
*/
|
57 |
+
const TRANSIENT_WCTRACKER_FEED_GENERATION_BATCH_WALL_START_TIME = 'facebook_for_woocommerce_wctracker_feed_generation_batch_wall_time';
|
58 |
+
|
59 |
/**
|
60 |
* Transient key name; true if feed has been requested by Facebook.
|
61 |
*
|
124 |
$data['extensions']['facebook-for-woocommerce']['messenger-enabled'] = wc_bool_to_string( $messenger_enabled );
|
125 |
|
126 |
/**
|
127 |
+
* How long did the last feed generation take (or did it fail - 0)? This counts just the time when the batches have been generated.
|
128 |
+
* It does not take into account the time between the batches.
|
129 |
*
|
130 |
* @since 2.6.0
|
131 |
*/
|
132 |
$feed_generation_time = get_transient( self::TRANSIENT_WCTRACKER_FEED_GENERATION_TIME );
|
133 |
$data['extensions']['facebook-for-woocommerce']['feed-generation-time'] = floatval( $feed_generation_time );
|
134 |
|
135 |
+
/**
|
136 |
+
* How long did the last feed generation take in wall time. This is the whole duration. Batches plus time in between.
|
137 |
+
*
|
138 |
+
* @since 2.6.6
|
139 |
+
*/
|
140 |
+
if ( facebook_for_woocommerce()->get_integration()->is_new_style_feed_generation_enabled() ) {
|
141 |
+
$feed_generation_batch_wall_time = intval( get_transient( self::TRANSIENT_WCTRACKER_FEED_GENERATION_BATCH_WALL_TIME ) );
|
142 |
+
} else {
|
143 |
+
// For old feed generator this is the same thing $feed_generation_time because the process is done in one step.
|
144 |
+
$feed_generation_batch_wall_time = intval( $feed_generation_time );
|
145 |
+
}
|
146 |
+
$data['extensions']['facebook-for-woocommerce']['feed-generation-wall-time'] = $feed_generation_batch_wall_time;
|
147 |
+
|
148 |
/**
|
149 |
* Has the feed file been requested since the last snapshot?
|
150 |
*
|
171 |
*/
|
172 |
$data['extensions']['facebook-for-woocommerce']['product-feed-config'] = get_transient( self::TRANSIENT_WCTRACKER_FB_FEED_CONFIG );
|
173 |
|
174 |
+
/**
|
175 |
+
* Detect if the user has enabled the new experimental feed generator feature.
|
176 |
+
*
|
177 |
+
* @since 2.6.6
|
178 |
+
*/
|
179 |
+
$data['extensions']['facebook-for-woocommerce']['new-feed-generator-enabled'] = wc_bool_to_string( facebook_for_woocommerce()->get_integration()->is_new_style_feed_generation_enabled() );
|
180 |
+
|
181 |
return $data;
|
182 |
}
|
183 |
|
193 |
set_transient( self::TRANSIENT_WCTRACKER_FEED_GENERATION_TIME, $time_in_seconds, self::TRANSIENT_WCTRACKER_LIFE_TIME );
|
194 |
}
|
195 |
|
196 |
+
/**
|
197 |
+
* Reset the feed generation in batch time counter.
|
198 |
+
*
|
199 |
+
* @since 2.6.6
|
200 |
+
*/
|
201 |
+
public function reset_batch_generation_time() {
|
202 |
+
// Reset the main counter.
|
203 |
+
$this->track_feed_file_generation_time( -1 );
|
204 |
+
set_transient( self::TRANSIENT_WCTRACKER_FEED_GENERATION_BATCH_TIME, 0, self::TRANSIENT_WCTRACKER_LIFE_TIME );
|
205 |
+
set_transient( self::TRANSIENT_WCTRACKER_FEED_GENERATION_BATCH_WALL_TIME, 0, self::TRANSIENT_WCTRACKER_LIFE_TIME );
|
206 |
+
set_transient( self::TRANSIENT_WCTRACKER_FEED_GENERATION_BATCH_WALL_START_TIME, time(), self::TRANSIENT_WCTRACKER_LIFE_TIME );
|
207 |
+
}
|
208 |
+
|
209 |
+
/**
|
210 |
+
* Add time to batch feed_generation_time.
|
211 |
+
* This accumulates time over all of the calculated feed batches.
|
212 |
+
*
|
213 |
+
* @param float $time_in_seconds Time to add to the generation time(in seconds).
|
214 |
+
* @since 2.6.6
|
215 |
+
*/
|
216 |
+
public function increment_batch_generation_time( $time_in_seconds ) {
|
217 |
+
$tracked_generation_time = floatval( get_transient( self::TRANSIENT_WCTRACKER_FEED_GENERATION_BATCH_TIME ) );
|
218 |
+
set_transient(
|
219 |
+
self::TRANSIENT_WCTRACKER_FEED_GENERATION_BATCH_TIME,
|
220 |
+
floatval( $time_in_seconds ) + $tracked_generation_time,
|
221 |
+
self::TRANSIENT_WCTRACKER_LIFE_TIME
|
222 |
+
);
|
223 |
+
}
|
224 |
+
|
225 |
+
/**
|
226 |
+
* Save batch generation time.
|
227 |
+
*
|
228 |
+
* This is the last step in batch feed generation time tracking.
|
229 |
+
* The accumulated time value is copied to the main transient
|
230 |
+
* that is later used by the tracking code to track feed generation time.
|
231 |
+
*
|
232 |
+
* @since 2.6.6
|
233 |
+
*/
|
234 |
+
public function save_batch_generation_time() {
|
235 |
+
$this->track_feed_file_generation_time(
|
236 |
+
get_transient( self::TRANSIENT_WCTRACKER_FEED_GENERATION_BATCH_TIME )
|
237 |
+
);
|
238 |
+
|
239 |
+
$start = intval( get_transient( self::TRANSIENT_WCTRACKER_FEED_GENERATION_BATCH_WALL_START_TIME ) );
|
240 |
+
$end = time();
|
241 |
+
set_transient(
|
242 |
+
self::TRANSIENT_WCTRACKER_FEED_GENERATION_BATCH_WALL_TIME,
|
243 |
+
$end - $start,
|
244 |
+
self::TRANSIENT_WCTRACKER_LIFE_TIME
|
245 |
+
);
|
246 |
+
}
|
247 |
+
|
248 |
/**
|
249 |
* Store the fact that the feed has been requested by Facebook in a transient.
|
250 |
* This will later be added to next tracker snapshot.
|
includes/fbproduct.php
CHANGED
@@ -56,15 +56,21 @@ if ( ! class_exists( 'WC_Facebook_Product' ) ) :
|
|
56 |
|
57 |
public function __construct( $wpid, $parent_product = null ) {
|
58 |
|
59 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
$this->fb_description = '';
|
61 |
-
$this->woo_product = wc_get_product( $wpid );
|
62 |
$this->gallery_urls = null;
|
63 |
$this->fb_use_parent_image = null;
|
64 |
$this->main_description = '';
|
65 |
$this->sync_short_description = \WC_Facebookcommerce_Integration::PRODUCT_DESCRIPTION_MODE_SHORT === facebook_for_woocommerce()->get_integration()->get_product_description_mode();
|
66 |
|
67 |
-
if ( $meta = get_post_meta( $
|
68 |
$this->fb_visibility = wc_string_to_bool( $meta );
|
69 |
} else {
|
70 |
$this->fb_visibility = '';
|
56 |
|
57 |
public function __construct( $wpid, $parent_product = null ) {
|
58 |
|
59 |
+
if ( $wpid instanceof WC_Product ) {
|
60 |
+
$this->id = $wpid->get_id();
|
61 |
+
$this->woo_product = $wpid;
|
62 |
+
} else {
|
63 |
+
$this->id = $wpid;
|
64 |
+
$this->woo_product = wc_get_product( $wpid );
|
65 |
+
}
|
66 |
+
|
67 |
$this->fb_description = '';
|
|
|
68 |
$this->gallery_urls = null;
|
69 |
$this->fb_use_parent_image = null;
|
70 |
$this->main_description = '';
|
71 |
$this->sync_short_description = \WC_Facebookcommerce_Integration::PRODUCT_DESCRIPTION_MODE_SHORT === facebook_for_woocommerce()->get_integration()->get_product_description_mode();
|
72 |
|
73 |
+
if ( $meta = get_post_meta( $this->id, self::FB_VISIBILITY, true ) ) {
|
74 |
$this->fb_visibility = wc_string_to_bool( $meta );
|
75 |
} else {
|
76 |
$this->fb_visibility = '';
|
includes/fbproductfeed.php
CHANGED
@@ -25,16 +25,9 @@ if ( ! class_exists( 'WC_Facebook_Product_Feed' ) ) :
|
|
25 |
class WC_Facebook_Product_Feed {
|
26 |
|
27 |
|
28 |
-
/** @var string transient name for storing the average feed generation time */
|
29 |
-
const TRANSIENT_AVERAGE_FEED_GENERATION_TIME = 'wc_facebook_average_feed_generation_time';
|
30 |
-
|
31 |
/** @var string product catalog feed file directory inside the uploads folder */
|
32 |
-
const UPLOADS_DIRECTORY
|
33 |
-
|
34 |
-
/** @var string product catalog feed file name - %s will be replaced with a hash */
|
35 |
-
const FILE_NAME = 'product_catalog_%s.csv';
|
36 |
-
|
37 |
-
|
38 |
const FACEBOOK_CATALOG_FEED_FILENAME = 'fae_product_catalog.csv';
|
39 |
const FB_ADDITIONAL_IMAGES_FOR_FEED = 5;
|
40 |
const FEED_NAME = 'Initial product sync from WooCommerce. DO NOT DELETE.';
|
@@ -58,30 +51,6 @@ if ( ! class_exists( 'WC_Facebook_Product_Feed' ) ) :
|
|
58 |
$this->feed_id = $feed_id;
|
59 |
}
|
60 |
|
61 |
-
|
62 |
-
/**
|
63 |
-
* Schedules a new feed generation.
|
64 |
-
*
|
65 |
-
* @since 1.11.0
|
66 |
-
*/
|
67 |
-
public function schedule_feed_generation() {
|
68 |
-
|
69 |
-
// don't schedule another if one's already scheduled or in progress
|
70 |
-
if ( false !== as_next_scheduled_action( 'wc_facebook_generate_product_catalog_feed', array(), 'facebook-for-woocommerce' ) ) {
|
71 |
-
return;
|
72 |
-
}
|
73 |
-
|
74 |
-
\WC_Facebookcommerce_Utils::log( 'Scheduling product catalog feed file generation' );
|
75 |
-
|
76 |
-
// if async priority actions are supported (AS 3.0+)
|
77 |
-
if ( function_exists( 'as_enqueue_async_action' ) ) {
|
78 |
-
as_enqueue_async_action( 'wc_facebook_generate_product_catalog_feed', array(), 'facebook-for-woocommerce' );
|
79 |
-
} else {
|
80 |
-
as_schedule_single_action( time(), 'wc_facebook_generate_product_catalog_feed', array(), 'facebook-for-woocommerce' );
|
81 |
-
}
|
82 |
-
}
|
83 |
-
|
84 |
-
|
85 |
/**
|
86 |
* Generates the product catalog feed.
|
87 |
*
|
@@ -104,8 +73,6 @@ if ( ! class_exists( 'WC_Facebook_Product_Feed' ) ) :
|
|
104 |
$generation_time = microtime( true ) - $start_time;
|
105 |
facebook_for_woocommerce()->get_tracker()->track_feed_file_generation_time( $generation_time );
|
106 |
|
107 |
-
$this->set_feed_generation_time_with_decay( $generation_time );
|
108 |
-
|
109 |
\WC_Facebookcommerce_Utils::log( 'Product feed file generated' );
|
110 |
|
111 |
} catch ( \Exception $exception ) {
|
@@ -119,165 +86,6 @@ if ( ! class_exists( 'WC_Facebook_Product_Feed' ) ) :
|
|
119 |
$profiling_logger->stop( 'generate_feed' );
|
120 |
}
|
121 |
|
122 |
-
|
123 |
-
/**
|
124 |
-
* Sets the average feed generation time with a 25% decay.
|
125 |
-
*
|
126 |
-
* @since 1.11.0
|
127 |
-
*
|
128 |
-
* @param float $generation_time last generation time
|
129 |
-
*/
|
130 |
-
private function set_feed_generation_time_with_decay( $generation_time ) {
|
131 |
-
|
132 |
-
// update feed generation time estimate w/ 25% decay.
|
133 |
-
$existing_generation_time = $this->get_average_feed_generation_time();
|
134 |
-
|
135 |
-
if ( $generation_time < $existing_generation_time ) {
|
136 |
-
$generation_time = $generation_time * 0.25 + $existing_generation_time * 0.75;
|
137 |
-
}
|
138 |
-
|
139 |
-
$this->set_average_feed_generation_time( $generation_time );
|
140 |
-
}
|
141 |
-
|
142 |
-
|
143 |
-
/**
|
144 |
-
* Sets the average feed generation time.
|
145 |
-
*
|
146 |
-
* @since 1.11.0
|
147 |
-
*
|
148 |
-
* @param float $time generation time
|
149 |
-
*/
|
150 |
-
private function set_average_feed_generation_time( $time ) {
|
151 |
-
|
152 |
-
set_transient( self::TRANSIENT_AVERAGE_FEED_GENERATION_TIME, $time );
|
153 |
-
}
|
154 |
-
|
155 |
-
|
156 |
-
/**
|
157 |
-
* Gets the estimated feed generation time.
|
158 |
-
*
|
159 |
-
* Performs a dry run and returns either the dry run time or last average estimated time, whichever is higher.
|
160 |
-
*
|
161 |
-
* @since 1.11.0
|
162 |
-
*
|
163 |
-
* @return int
|
164 |
-
*/
|
165 |
-
public function get_estimated_feed_generation_time() {
|
166 |
-
|
167 |
-
$estimate = $this->estimate_generation_time();
|
168 |
-
$average = $this->get_average_feed_generation_time();
|
169 |
-
|
170 |
-
return (int) max( $estimate, $average );
|
171 |
-
}
|
172 |
-
|
173 |
-
|
174 |
-
/**
|
175 |
-
* Estimates the feed generation time.
|
176 |
-
*
|
177 |
-
* Runs a dry-run generation of a subset of products, then extrapolates that out to the full catalog size. Also
|
178 |
-
* adds a bit of buffer time.
|
179 |
-
*
|
180 |
-
* @since 1.11.0
|
181 |
-
*
|
182 |
-
* @return float
|
183 |
-
*/
|
184 |
-
private function estimate_generation_time() {
|
185 |
-
|
186 |
-
$product_ids = $this->get_product_ids();
|
187 |
-
$total_products = count( $product_ids );
|
188 |
-
$sample_size = $this->get_feed_generation_estimate_sample_size();
|
189 |
-
$buffer_time = $this->get_feed_generation_buffer_time();
|
190 |
-
|
191 |
-
if ( $total_products > 0 ) {
|
192 |
-
|
193 |
-
if ( $total_products < $sample_size ) {
|
194 |
-
|
195 |
-
$sample_size = $total_products;
|
196 |
-
|
197 |
-
} else {
|
198 |
-
|
199 |
-
$product_ids = array_slice( $product_ids, 0, $sample_size );
|
200 |
-
}
|
201 |
-
|
202 |
-
$start_time = microtime( true );
|
203 |
-
|
204 |
-
$this->write_product_feed_file( $product_ids, true );
|
205 |
-
|
206 |
-
$end_time = microtime( true );
|
207 |
-
|
208 |
-
$time_spent = $end_time - $start_time;
|
209 |
-
|
210 |
-
// estimated Time = 150% of Linear extrapolation of the time to generate n products + buffer time.
|
211 |
-
$time_estimate = $time_spent * $total_products / $sample_size * 1.5 + $buffer_time;
|
212 |
-
|
213 |
-
} else {
|
214 |
-
|
215 |
-
$time_estimate = $buffer_time;
|
216 |
-
}
|
217 |
-
|
218 |
-
WC_Facebookcommerce_Utils::log( 'Feed Generation Time Estimate: ' . $time_estimate );
|
219 |
-
|
220 |
-
return $time_estimate;
|
221 |
-
}
|
222 |
-
|
223 |
-
|
224 |
-
/**
|
225 |
-
* Gets the average feed generation time.
|
226 |
-
*
|
227 |
-
* @since 1.11.0
|
228 |
-
*
|
229 |
-
* @return float
|
230 |
-
*/
|
231 |
-
private function get_average_feed_generation_time() {
|
232 |
-
|
233 |
-
return get_transient( self::TRANSIENT_AVERAGE_FEED_GENERATION_TIME );
|
234 |
-
}
|
235 |
-
|
236 |
-
|
237 |
-
/**
|
238 |
-
* Gets the number of products to use when estimating the feed file generation time.
|
239 |
-
*
|
240 |
-
* @since 1.11.0
|
241 |
-
*
|
242 |
-
* @return int
|
243 |
-
*/
|
244 |
-
private function get_feed_generation_estimate_sample_size() {
|
245 |
-
|
246 |
-
/**
|
247 |
-
* Filters the number of products to use when estimating the feed file generation time.
|
248 |
-
*
|
249 |
-
* @since 1.11.0
|
250 |
-
*
|
251 |
-
* @param int $sample_size number of products to use when estimating the feed file generation time
|
252 |
-
*/
|
253 |
-
$sample_size = (int) apply_filters( 'wc_facebook_product_catalog_feed_generation_estimate_sample_size', 200 );
|
254 |
-
|
255 |
-
return max( $sample_size, 100 );
|
256 |
-
}
|
257 |
-
|
258 |
-
|
259 |
-
/**
|
260 |
-
* Gets the number of seconds to add as a buffer when estimating the feed file generation time.
|
261 |
-
*
|
262 |
-
* @since 1.11.0
|
263 |
-
*
|
264 |
-
* @return int
|
265 |
-
*/
|
266 |
-
private function get_feed_generation_buffer_time() {
|
267 |
-
|
268 |
-
/**
|
269 |
-
* Filters the number of seconds to add as a buffer when estimating the feed file generation time.
|
270 |
-
*
|
271 |
-
* @since 1.11.0
|
272 |
-
*
|
273 |
-
* @param int $time number of seconds to add as a buffer when estimating the feed file generation time
|
274 |
-
*/
|
275 |
-
$buffer_time = (int) apply_filters( 'wc_facebook_product_catalog_feed_generation_buffer_time', 30 );
|
276 |
-
|
277 |
-
return max( $buffer_time, 5 );
|
278 |
-
}
|
279 |
-
|
280 |
-
|
281 |
/**
|
282 |
* Gets the product catalog feed file path.
|
283 |
*
|
@@ -481,7 +289,7 @@ if ( ! class_exists( 'WC_Facebook_Product_Feed' ) ) :
|
|
481 |
*
|
482 |
* @since 1.11.0
|
483 |
*/
|
484 |
-
|
485 |
|
486 |
$catalog_feed_directory = trailingslashit( $this->get_file_directory() );
|
487 |
|
@@ -518,96 +326,133 @@ if ( ! class_exists( 'WC_Facebook_Product_Feed' ) ) :
|
|
518 |
* @since 1.11.0
|
519 |
*
|
520 |
* @param int[] $wp_ids product IDs
|
521 |
-
* @param bool $is_dry_run whether this is a dry run or the file should be written
|
522 |
* @return bool
|
523 |
*/
|
524 |
-
public function write_product_feed_file( $wp_ids
|
525 |
|
526 |
try {
|
527 |
|
528 |
-
|
|
|
529 |
|
530 |
-
|
531 |
-
|
532 |
|
533 |
-
|
534 |
-
|
535 |
-
throw new Framework\SV_WC_Plugin_Exception( __( 'Could not open the product catalog temporary feed file for writing', 'facebook-for-woocommerce' ), 500 );
|
536 |
-
}
|
537 |
|
538 |
-
|
539 |
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
}
|
544 |
|
545 |
-
|
|
|
|
|
|
|
|
|
|
|
546 |
}
|
547 |
|
548 |
-
|
|
|
549 |
|
550 |
-
|
|
|
|
|
551 |
|
552 |
-
|
|
|
553 |
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
558 |
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
|
564 |
-
|
565 |
-
$woo_product,
|
566 |
-
$product_group_attribute_variants
|
567 |
-
);
|
568 |
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
|
574 |
-
|
|
|
|
|
575 |
|
576 |
-
|
577 |
-
|
578 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
579 |
|
580 |
-
|
581 |
|
582 |
-
|
583 |
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
}
|
588 |
|
589 |
-
|
|
|
|
|
|
|
590 |
|
591 |
-
|
|
|
|
|
|
|
592 |
|
593 |
-
|
|
|
|
|
|
|
594 |
|
595 |
-
|
596 |
|
597 |
-
|
598 |
-
|
|
|
|
|
599 |
|
600 |
-
|
601 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
602 |
|
603 |
-
|
604 |
-
if ( ! empty( $temp_file_path ) && file_exists( $temp_file_path ) ) {
|
605 |
|
606 |
-
|
|
|
607 |
}
|
608 |
}
|
609 |
-
|
610 |
-
return $written;
|
611 |
}
|
612 |
|
613 |
public function get_product_feed_header_row() {
|
25 |
class WC_Facebook_Product_Feed {
|
26 |
|
27 |
|
|
|
|
|
|
|
28 |
/** @var string product catalog feed file directory inside the uploads folder */
|
29 |
+
const UPLOADS_DIRECTORY = 'facebook_for_woocommerce';
|
30 |
+
const FILE_NAME = 'product_catalog_%s.csv';
|
|
|
|
|
|
|
|
|
31 |
const FACEBOOK_CATALOG_FEED_FILENAME = 'fae_product_catalog.csv';
|
32 |
const FB_ADDITIONAL_IMAGES_FOR_FEED = 5;
|
33 |
const FEED_NAME = 'Initial product sync from WooCommerce. DO NOT DELETE.';
|
51 |
$this->feed_id = $feed_id;
|
52 |
}
|
53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
/**
|
55 |
* Generates the product catalog feed.
|
56 |
*
|
73 |
$generation_time = microtime( true ) - $start_time;
|
74 |
facebook_for_woocommerce()->get_tracker()->track_feed_file_generation_time( $generation_time );
|
75 |
|
|
|
|
|
76 |
\WC_Facebookcommerce_Utils::log( 'Product feed file generated' );
|
77 |
|
78 |
} catch ( \Exception $exception ) {
|
86 |
$profiling_logger->stop( 'generate_feed' );
|
87 |
}
|
88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
/**
|
90 |
* Gets the product catalog feed file path.
|
91 |
*
|
289 |
*
|
290 |
* @since 1.11.0
|
291 |
*/
|
292 |
+
public function create_files_to_protect_product_feed_directory() {
|
293 |
|
294 |
$catalog_feed_directory = trailingslashit( $this->get_file_directory() );
|
295 |
|
326 |
* @since 1.11.0
|
327 |
*
|
328 |
* @param int[] $wp_ids product IDs
|
|
|
329 |
* @return bool
|
330 |
*/
|
331 |
+
public function write_product_feed_file( $wp_ids ) {
|
332 |
|
333 |
try {
|
334 |
|
335 |
+
// Step 1: Prepare the temporary empty feed file with header row.
|
336 |
+
$temp_feed_file = $this->prepare_temporary_feed_file();
|
337 |
|
338 |
+
// Step 2: Write products feed into the temporary feed file.
|
339 |
+
$this->write_products_feed_to_temp_file( $wp_ids, $temp_feed_file );
|
340 |
|
341 |
+
// Step 3: Rename temporary feed file to final feed file.
|
342 |
+
$this->rename_temporary_feed_file_to_final_feed_file();
|
|
|
|
|
343 |
|
344 |
+
$written = true;
|
345 |
|
346 |
+
} catch ( Exception $e ) {
|
347 |
+
|
348 |
+
WC_Facebookcommerce_Utils::log( json_encode( $e->getMessage() ) );
|
|
|
349 |
|
350 |
+
$written = false;
|
351 |
+
|
352 |
+
// close the temporary file
|
353 |
+
if ( ! empty( $temp_feed_file ) && is_resource( $temp_feed_file ) ) {
|
354 |
+
|
355 |
+
fclose( $temp_feed_file );
|
356 |
}
|
357 |
|
358 |
+
// delete the temporary file
|
359 |
+
if ( ! empty( $temp_file_path ) && file_exists( $temp_file_path ) ) {
|
360 |
|
361 |
+
unlink( $temp_file_path );
|
362 |
+
}
|
363 |
+
}
|
364 |
|
365 |
+
return $written;
|
366 |
+
}
|
367 |
|
368 |
+
/**
|
369 |
+
* Prepare a fresh empty temporary feed file with the header row.
|
370 |
+
*
|
371 |
+
* @since 2.6.6
|
372 |
+
*
|
373 |
+
* @throws Framework\SV_WC_Plugin_Exception We can't open the file or the file is not writable.
|
374 |
+
* @return resource A file pointer resource.
|
375 |
+
*/
|
376 |
+
public function prepare_temporary_feed_file() {
|
377 |
+
$temp_file_path = $this->get_temp_file_path();
|
378 |
+
$temp_feed_file = @fopen( $temp_file_path, 'w' );
|
379 |
|
380 |
+
// check if we can open the temporary feed file
|
381 |
+
if ( false === $temp_feed_file || ! is_writable( $temp_file_path ) ) {
|
382 |
+
throw new Framework\SV_WC_Plugin_Exception( __( 'Could not open the product catalog temporary feed file for writing', 'facebook-for-woocommerce' ), 500 );
|
383 |
+
}
|
384 |
|
385 |
+
$file_path = $this->get_file_path();
|
|
|
|
|
|
|
386 |
|
387 |
+
// check if we will be able to write to the final feed file
|
388 |
+
if ( file_exists( $file_path ) && ! is_writable( $file_path ) ) {
|
389 |
+
throw new Framework\SV_WC_Plugin_Exception( __( 'Could not open the product catalog feed file for writing', 'facebook-for-woocommerce' ), 500 );
|
390 |
+
}
|
391 |
|
392 |
+
fwrite( $temp_feed_file, $this->get_product_feed_header_row() );
|
393 |
+
return $temp_feed_file;
|
394 |
+
}
|
395 |
|
396 |
+
/**
|
397 |
+
* Write products feed into a file.
|
398 |
+
*
|
399 |
+
* @since 2.6.6
|
400 |
+
*
|
401 |
+
* @return void
|
402 |
+
*/
|
403 |
+
public function write_products_feed_to_temp_file( $wp_ids, $temp_feed_file ) {
|
404 |
+
$product_group_attribute_variants = array();
|
405 |
|
406 |
+
foreach ( $wp_ids as $wp_id ) {
|
407 |
|
408 |
+
$woo_product = new WC_Facebook_Product( $wp_id );
|
409 |
|
410 |
+
// Skip if we don't have a valid product object.
|
411 |
+
if ( ! $woo_product->woo_product instanceof \WC_Product ) {
|
412 |
+
continue;
|
413 |
}
|
414 |
|
415 |
+
// Skip if not enabled for sync.
|
416 |
+
if ( ! facebook_for_woocommerce()->get_product_sync_validator( $woo_product->woo_product )->passes_all_checks() ) {
|
417 |
+
continue;
|
418 |
+
}
|
419 |
|
420 |
+
$product_data_as_feed_row = $this->prepare_product_for_feed(
|
421 |
+
$woo_product,
|
422 |
+
$product_group_attribute_variants
|
423 |
+
);
|
424 |
|
425 |
+
if ( ! empty( $temp_feed_file ) ) {
|
426 |
+
fwrite( $temp_feed_file, $product_data_as_feed_row );
|
427 |
+
}
|
428 |
+
}
|
429 |
|
430 |
+
wp_reset_postdata();
|
431 |
|
432 |
+
if ( ! empty( $temp_feed_file ) ) {
|
433 |
+
fclose( $temp_feed_file );
|
434 |
+
}
|
435 |
+
}
|
436 |
|
437 |
+
/**
|
438 |
+
* Rename temporary feed file into the final feed file.
|
439 |
+
* This is the last step fo the feed generation procedure.
|
440 |
+
*
|
441 |
+
* @since 2.6.6
|
442 |
+
*
|
443 |
+
* @return void
|
444 |
+
*/
|
445 |
+
public function rename_temporary_feed_file_to_final_feed_file() {
|
446 |
+
$file_path = $this->get_file_path();
|
447 |
+
$temp_file_path = $this->get_temp_file_path();
|
448 |
+
if ( ! empty( $temp_file_path ) && ! empty( $file_path ) ) {
|
449 |
|
450 |
+
$renamed = rename( $temp_file_path, $file_path );
|
|
|
451 |
|
452 |
+
if ( empty( $renamed ) ) {
|
453 |
+
throw new Framework\SV_WC_Plugin_Exception( __( 'Could not rename the product catalog feed file', 'facebook-for-woocommerce' ), 500 );
|
454 |
}
|
455 |
}
|
|
|
|
|
456 |
}
|
457 |
|
458 |
public function get_product_feed_header_row() {
|
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.8
|
6 |
-
Stable tag: 2.6.
|
7 |
Requires PHP: 5.6 or greater
|
8 |
MySQL: 5.6 or greater
|
9 |
License: GPLv2 or later
|
@@ -39,7 +39,17 @@ When opening a bug on GitHub, please give us as many details as possible.
|
|
39 |
|
40 |
== Changelog ==
|
41 |
|
42 |
-
= 2.6.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
* Fix - Incorrect `is_readable()` usage when loading Integration classes.
|
44 |
* Tweak - WC 5.7 compatibility.
|
45 |
* Tweak - WP 5.8 compatibility.
|
2 |
Contributors: facebook, automattic, woothemes
|
3 |
Tags: facebook, shop, catalog, advertise, pixel, product
|
4 |
Requires at least: 4.4
|
5 |
+
Tested up to: 5.8
|
6 |
+
Stable tag: 2.6.6
|
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.6 - 2021-11-03 =
|
43 |
+
* New - Memory improved feed generation process. #2099
|
44 |
+
* New - Add compatibility with the WooCommerce checkout block. #2095
|
45 |
+
* New - Track batched feed generation time in the tracker snapshots. #2104
|
46 |
+
* New - Track usage of the new style feed generator in the tracker snapshots. #2103
|
47 |
+
* New - Hide headers in logs for better visibility. #2093
|
48 |
+
* Dev - Update composer dependencies. #2090
|
49 |
+
* New - Add no synchronization reason to the product edit screen in the Facebook meta box. #1937
|
50 |
+
* Fix - Use published variations only for the default variation. #2091
|
51 |
+
|
52 |
+
= 2.6.5 - 2021-09-16 =
|
53 |
* Fix - Incorrect `is_readable()` usage when loading Integration classes.
|
54 |
* Tweak - WC 5.7 compatibility.
|
55 |
* Tweak - WP 5.8 compatibility.
|
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 ComposerAutoloaderInitde7d5bed3e120a58eb0e6fe4bc2b3a15::getLoader();
|
vendor/composer/ClassLoader.php
CHANGED
@@ -42,21 +42,75 @@ namespace Composer\Autoload;
|
|
42 |
*/
|
43 |
class ClassLoader
|
44 |
{
|
|
|
|
|
|
|
45 |
// PSR-4
|
|
|
|
|
|
|
|
|
46 |
private $prefixLengthsPsr4 = array();
|
|
|
|
|
|
|
|
|
47 |
private $prefixDirsPsr4 = array();
|
|
|
|
|
|
|
|
|
48 |
private $fallbackDirsPsr4 = array();
|
49 |
|
50 |
// PSR-0
|
|
|
|
|
|
|
|
|
51 |
private $prefixesPsr0 = array();
|
|
|
|
|
|
|
|
|
52 |
private $fallbackDirsPsr0 = array();
|
53 |
|
|
|
54 |
private $useIncludePath = false;
|
|
|
|
|
|
|
|
|
|
|
55 |
private $classMap = array();
|
|
|
|
|
56 |
private $classMapAuthoritative = false;
|
|
|
|
|
|
|
|
|
|
|
57 |
private $missingClasses = array();
|
|
|
|
|
58 |
private $apcuPrefix;
|
59 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
public function getPrefixes()
|
61 |
{
|
62 |
if (!empty($this->prefixesPsr0)) {
|
@@ -66,28 +120,47 @@ class ClassLoader
|
|
66 |
return array();
|
67 |
}
|
68 |
|
|
|
|
|
|
|
|
|
69 |
public function getPrefixesPsr4()
|
70 |
{
|
71 |
return $this->prefixDirsPsr4;
|
72 |
}
|
73 |
|
|
|
|
|
|
|
|
|
74 |
public function getFallbackDirs()
|
75 |
{
|
76 |
return $this->fallbackDirsPsr0;
|
77 |
}
|
78 |
|
|
|
|
|
|
|
|
|
79 |
public function getFallbackDirsPsr4()
|
80 |
{
|
81 |
return $this->fallbackDirsPsr4;
|
82 |
}
|
83 |
|
|
|
|
|
|
|
|
|
84 |
public function getClassMap()
|
85 |
{
|
86 |
return $this->classMap;
|
87 |
}
|
88 |
|
89 |
/**
|
90 |
-
* @param
|
|
|
|
|
|
|
91 |
*/
|
92 |
public function addClassMap(array $classMap)
|
93 |
{
|
@@ -102,9 +175,11 @@ class ClassLoader
|
|
102 |
* Registers a set of PSR-0 directories for a given prefix, either
|
103 |
* appending or prepending to the ones previously set for this prefix.
|
104 |
*
|
105 |
-
* @param string
|
106 |
-
* @param
|
107 |
-
* @param bool
|
|
|
|
|
108 |
*/
|
109 |
public function add($prefix, $paths, $prepend = false)
|
110 |
{
|
@@ -147,11 +222,13 @@ class ClassLoader
|
|
147 |
* Registers a set of PSR-4 directories for a given namespace, either
|
148 |
* appending or prepending to the ones previously set for this namespace.
|
149 |
*
|
150 |
-
* @param string
|
151 |
-
* @param
|
152 |
-
* @param bool
|
153 |
*
|
154 |
* @throws \InvalidArgumentException
|
|
|
|
|
155 |
*/
|
156 |
public function addPsr4($prefix, $paths, $prepend = false)
|
157 |
{
|
@@ -195,8 +272,10 @@ class ClassLoader
|
|
195 |
* Registers a set of PSR-0 directories for a given prefix,
|
196 |
* replacing any others previously set for this prefix.
|
197 |
*
|
198 |
-
* @param string
|
199 |
-
* @param
|
|
|
|
|
200 |
*/
|
201 |
public function set($prefix, $paths)
|
202 |
{
|
@@ -211,10 +290,12 @@ class ClassLoader
|
|
211 |
* Registers a set of PSR-4 directories for a given namespace,
|
212 |
* replacing any others previously set for this namespace.
|
213 |
*
|
214 |
-
* @param string
|
215 |
-
* @param
|
216 |
*
|
217 |
* @throws \InvalidArgumentException
|
|
|
|
|
218 |
*/
|
219 |
public function setPsr4($prefix, $paths)
|
220 |
{
|
@@ -234,6 +315,8 @@ class ClassLoader
|
|
234 |
* Turns on searching the include path for class files.
|
235 |
*
|
236 |
* @param bool $useIncludePath
|
|
|
|
|
237 |
*/
|
238 |
public function setUseIncludePath($useIncludePath)
|
239 |
{
|
@@ -256,6 +339,8 @@ class ClassLoader
|
|
256 |
* that have not been registered with the class map.
|
257 |
*
|
258 |
* @param bool $classMapAuthoritative
|
|
|
|
|
259 |
*/
|
260 |
public function setClassMapAuthoritative($classMapAuthoritative)
|
261 |
{
|
@@ -276,6 +361,8 @@ class ClassLoader
|
|
276 |
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
277 |
*
|
278 |
* @param string|null $apcuPrefix
|
|
|
|
|
279 |
*/
|
280 |
public function setApcuPrefix($apcuPrefix)
|
281 |
{
|
@@ -296,25 +383,44 @@ class ClassLoader
|
|
296 |
* Registers this instance as an autoloader.
|
297 |
*
|
298 |
* @param bool $prepend Whether to prepend the autoloader or not
|
|
|
|
|
299 |
*/
|
300 |
public function register($prepend = false)
|
301 |
{
|
302 |
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
303 |
}
|
304 |
|
305 |
/**
|
306 |
* Unregisters this instance as an autoloader.
|
|
|
|
|
307 |
*/
|
308 |
public function unregister()
|
309 |
{
|
310 |
spl_autoload_unregister(array($this, 'loadClass'));
|
|
|
|
|
|
|
|
|
311 |
}
|
312 |
|
313 |
/**
|
314 |
* Loads the given class or interface.
|
315 |
*
|
316 |
* @param string $class The name of the class
|
317 |
-
* @return
|
318 |
*/
|
319 |
public function loadClass($class)
|
320 |
{
|
@@ -323,6 +429,8 @@ class ClassLoader
|
|
323 |
|
324 |
return true;
|
325 |
}
|
|
|
|
|
326 |
}
|
327 |
|
328 |
/**
|
@@ -367,6 +475,21 @@ class ClassLoader
|
|
367 |
return $file;
|
368 |
}
|
369 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
370 |
private function findFileWithExtension($class, $ext)
|
371 |
{
|
372 |
// PSR-4 lookup
|
@@ -438,6 +561,10 @@ class ClassLoader
|
|
438 |
* Scope isolated include.
|
439 |
*
|
440 |
* Prevents access to $this/self from included files.
|
|
|
|
|
|
|
|
|
441 |
*/
|
442 |
function includeFile($file)
|
443 |
{
|
42 |
*/
|
43 |
class ClassLoader
|
44 |
{
|
45 |
+
/** @var ?string */
|
46 |
+
private $vendorDir;
|
47 |
+
|
48 |
// PSR-4
|
49 |
+
/**
|
50 |
+
* @var array[]
|
51 |
+
* @psalm-var array<string, array<string, int>>
|
52 |
+
*/
|
53 |
private $prefixLengthsPsr4 = array();
|
54 |
+
/**
|
55 |
+
* @var array[]
|
56 |
+
* @psalm-var array<string, array<int, string>>
|
57 |
+
*/
|
58 |
private $prefixDirsPsr4 = array();
|
59 |
+
/**
|
60 |
+
* @var array[]
|
61 |
+
* @psalm-var array<string, string>
|
62 |
+
*/
|
63 |
private $fallbackDirsPsr4 = array();
|
64 |
|
65 |
// PSR-0
|
66 |
+
/**
|
67 |
+
* @var array[]
|
68 |
+
* @psalm-var array<string, array<string, string[]>>
|
69 |
+
*/
|
70 |
private $prefixesPsr0 = array();
|
71 |
+
/**
|
72 |
+
* @var array[]
|
73 |
+
* @psalm-var array<string, string>
|
74 |
+
*/
|
75 |
private $fallbackDirsPsr0 = array();
|
76 |
|
77 |
+
/** @var bool */
|
78 |
private $useIncludePath = false;
|
79 |
+
|
80 |
+
/**
|
81 |
+
* @var string[]
|
82 |
+
* @psalm-var array<string, string>
|
83 |
+
*/
|
84 |
private $classMap = array();
|
85 |
+
|
86 |
+
/** @var bool */
|
87 |
private $classMapAuthoritative = false;
|
88 |
+
|
89 |
+
/**
|
90 |
+
* @var bool[]
|
91 |
+
* @psalm-var array<string, bool>
|
92 |
+
*/
|
93 |
private $missingClasses = array();
|
94 |
+
|
95 |
+
/** @var ?string */
|
96 |
private $apcuPrefix;
|
97 |
|
98 |
+
/**
|
99 |
+
* @var self[]
|
100 |
+
*/
|
101 |
+
private static $registeredLoaders = array();
|
102 |
+
|
103 |
+
/**
|
104 |
+
* @param ?string $vendorDir
|
105 |
+
*/
|
106 |
+
public function __construct($vendorDir = null)
|
107 |
+
{
|
108 |
+
$this->vendorDir = $vendorDir;
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* @return string[]
|
113 |
+
*/
|
114 |
public function getPrefixes()
|
115 |
{
|
116 |
if (!empty($this->prefixesPsr0)) {
|
120 |
return array();
|
121 |
}
|
122 |
|
123 |
+
/**
|
124 |
+
* @return array[]
|
125 |
+
* @psalm-return array<string, array<int, string>>
|
126 |
+
*/
|
127 |
public function getPrefixesPsr4()
|
128 |
{
|
129 |
return $this->prefixDirsPsr4;
|
130 |
}
|
131 |
|
132 |
+
/**
|
133 |
+
* @return array[]
|
134 |
+
* @psalm-return array<string, string>
|
135 |
+
*/
|
136 |
public function getFallbackDirs()
|
137 |
{
|
138 |
return $this->fallbackDirsPsr0;
|
139 |
}
|
140 |
|
141 |
+
/**
|
142 |
+
* @return array[]
|
143 |
+
* @psalm-return array<string, string>
|
144 |
+
*/
|
145 |
public function getFallbackDirsPsr4()
|
146 |
{
|
147 |
return $this->fallbackDirsPsr4;
|
148 |
}
|
149 |
|
150 |
+
/**
|
151 |
+
* @return string[] Array of classname => path
|
152 |
+
* @psalm-var array<string, string>
|
153 |
+
*/
|
154 |
public function getClassMap()
|
155 |
{
|
156 |
return $this->classMap;
|
157 |
}
|
158 |
|
159 |
/**
|
160 |
+
* @param string[] $classMap Class to filename map
|
161 |
+
* @psalm-param array<string, string> $classMap
|
162 |
+
*
|
163 |
+
* @return void
|
164 |
*/
|
165 |
public function addClassMap(array $classMap)
|
166 |
{
|
175 |
* Registers a set of PSR-0 directories for a given prefix, either
|
176 |
* appending or prepending to the ones previously set for this prefix.
|
177 |
*
|
178 |
+
* @param string $prefix The prefix
|
179 |
+
* @param string[]|string $paths The PSR-0 root directories
|
180 |
+
* @param bool $prepend Whether to prepend the directories
|
181 |
+
*
|
182 |
+
* @return void
|
183 |
*/
|
184 |
public function add($prefix, $paths, $prepend = false)
|
185 |
{
|
222 |
* Registers a set of PSR-4 directories for a given namespace, either
|
223 |
* appending or prepending to the ones previously set for this namespace.
|
224 |
*
|
225 |
+
* @param string $prefix The prefix/namespace, with trailing '\\'
|
226 |
+
* @param string[]|string $paths The PSR-4 base directories
|
227 |
+
* @param bool $prepend Whether to prepend the directories
|
228 |
*
|
229 |
* @throws \InvalidArgumentException
|
230 |
+
*
|
231 |
+
* @return void
|
232 |
*/
|
233 |
public function addPsr4($prefix, $paths, $prepend = false)
|
234 |
{
|
272 |
* Registers a set of PSR-0 directories for a given prefix,
|
273 |
* replacing any others previously set for this prefix.
|
274 |
*
|
275 |
+
* @param string $prefix The prefix
|
276 |
+
* @param string[]|string $paths The PSR-0 base directories
|
277 |
+
*
|
278 |
+
* @return void
|
279 |
*/
|
280 |
public function set($prefix, $paths)
|
281 |
{
|
290 |
* Registers a set of PSR-4 directories for a given namespace,
|
291 |
* replacing any others previously set for this namespace.
|
292 |
*
|
293 |
+
* @param string $prefix The prefix/namespace, with trailing '\\'
|
294 |
+
* @param string[]|string $paths The PSR-4 base directories
|
295 |
*
|
296 |
* @throws \InvalidArgumentException
|
297 |
+
*
|
298 |
+
* @return void
|
299 |
*/
|
300 |
public function setPsr4($prefix, $paths)
|
301 |
{
|
315 |
* Turns on searching the include path for class files.
|
316 |
*
|
317 |
* @param bool $useIncludePath
|
318 |
+
*
|
319 |
+
* @return void
|
320 |
*/
|
321 |
public function setUseIncludePath($useIncludePath)
|
322 |
{
|
339 |
* that have not been registered with the class map.
|
340 |
*
|
341 |
* @param bool $classMapAuthoritative
|
342 |
+
*
|
343 |
+
* @return void
|
344 |
*/
|
345 |
public function setClassMapAuthoritative($classMapAuthoritative)
|
346 |
{
|
361 |
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
362 |
*
|
363 |
* @param string|null $apcuPrefix
|
364 |
+
*
|
365 |
+
* @return void
|
366 |
*/
|
367 |
public function setApcuPrefix($apcuPrefix)
|
368 |
{
|
383 |
* Registers this instance as an autoloader.
|
384 |
*
|
385 |
* @param bool $prepend Whether to prepend the autoloader or not
|
386 |
+
*
|
387 |
+
* @return void
|
388 |
*/
|
389 |
public function register($prepend = false)
|
390 |
{
|
391 |
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
392 |
+
|
393 |
+
if (null === $this->vendorDir) {
|
394 |
+
return;
|
395 |
+
}
|
396 |
+
|
397 |
+
if ($prepend) {
|
398 |
+
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
399 |
+
} else {
|
400 |
+
unset(self::$registeredLoaders[$this->vendorDir]);
|
401 |
+
self::$registeredLoaders[$this->vendorDir] = $this;
|
402 |
+
}
|
403 |
}
|
404 |
|
405 |
/**
|
406 |
* Unregisters this instance as an autoloader.
|
407 |
+
*
|
408 |
+
* @return void
|
409 |
*/
|
410 |
public function unregister()
|
411 |
{
|
412 |
spl_autoload_unregister(array($this, 'loadClass'));
|
413 |
+
|
414 |
+
if (null !== $this->vendorDir) {
|
415 |
+
unset(self::$registeredLoaders[$this->vendorDir]);
|
416 |
+
}
|
417 |
}
|
418 |
|
419 |
/**
|
420 |
* Loads the given class or interface.
|
421 |
*
|
422 |
* @param string $class The name of the class
|
423 |
+
* @return true|null True if loaded, null otherwise
|
424 |
*/
|
425 |
public function loadClass($class)
|
426 |
{
|
429 |
|
430 |
return true;
|
431 |
}
|
432 |
+
|
433 |
+
return null;
|
434 |
}
|
435 |
|
436 |
/**
|
475 |
return $file;
|
476 |
}
|
477 |
|
478 |
+
/**
|
479 |
+
* Returns the currently registered loaders indexed by their corresponding vendor directories.
|
480 |
+
*
|
481 |
+
* @return self[]
|
482 |
+
*/
|
483 |
+
public static function getRegisteredLoaders()
|
484 |
+
{
|
485 |
+
return self::$registeredLoaders;
|
486 |
+
}
|
487 |
+
|
488 |
+
/**
|
489 |
+
* @param string $class
|
490 |
+
* @param string $ext
|
491 |
+
* @return string|false
|
492 |
+
*/
|
493 |
private function findFileWithExtension($class, $ext)
|
494 |
{
|
495 |
// PSR-4 lookup
|
561 |
* Scope isolated include.
|
562 |
*
|
563 |
* Prevents access to $this/self from included files.
|
564 |
+
*
|
565 |
+
* @param string $file
|
566 |
+
* @return void
|
567 |
+
* @private
|
568 |
*/
|
569 |
function includeFile($file)
|
570 |
{
|
vendor/composer/InstalledVersions.php
CHANGED
@@ -1,260 +1,337 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
|
13 |
namespace Composer;
|
14 |
|
|
|
15 |
use Composer\Semver\VersionParser;
|
16 |
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
|
|
|
|
22 |
class InstalledVersions
|
23 |
{
|
24 |
-
private static $installed
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
if (
|
158 |
-
|
159 |
-
}
|
160 |
-
|
161 |
-
|
162 |
-
}
|
163 |
-
|
164 |
-
|
165 |
-
}
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
public static function
|
172 |
-
{
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
self::$installed
|
259 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
260 |
}
|
1 |
<?php
|
2 |
|
3 |
+
/*
|
4 |
+
* This file is part of Composer.
|
5 |
+
*
|
6 |
+
* (c) Nils Adermann <naderman@naderman.de>
|
7 |
+
* Jordi Boggiano <j.boggiano@seld.be>
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
|
13 |
namespace Composer;
|
14 |
|
15 |
+
use Composer\Autoload\ClassLoader;
|
16 |
use Composer\Semver\VersionParser;
|
17 |
|
18 |
+
/**
|
19 |
+
* This class is copied in every Composer installed project and available to all
|
20 |
+
*
|
21 |
+
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
22 |
+
*
|
23 |
+
* To require its presence, you can require `composer-runtime-api ^2.0`
|
24 |
+
*/
|
25 |
class InstalledVersions
|
26 |
{
|
27 |
+
private static $installed;
|
28 |
+
private static $canGetVendors;
|
29 |
+
private static $installedByVendor = array();
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
33 |
+
*
|
34 |
+
* @return string[]
|
35 |
+
* @psalm-return list<string>
|
36 |
+
*/
|
37 |
+
public static function getInstalledPackages()
|
38 |
+
{
|
39 |
+
$packages = array();
|
40 |
+
foreach (self::getInstalled() as $installed) {
|
41 |
+
$packages[] = array_keys($installed['versions']);
|
42 |
+
}
|
43 |
+
|
44 |
+
if (1 === \count($packages)) {
|
45 |
+
return $packages[0];
|
46 |
+
}
|
47 |
+
|
48 |
+
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Returns a list of all package names with a specific type e.g. 'library'
|
53 |
+
*
|
54 |
+
* @param string $type
|
55 |
+
* @return string[]
|
56 |
+
* @psalm-return list<string>
|
57 |
+
*/
|
58 |
+
public static function getInstalledPackagesByType($type)
|
59 |
+
{
|
60 |
+
$packagesByType = array();
|
61 |
+
|
62 |
+
foreach (self::getInstalled() as $installed) {
|
63 |
+
foreach ($installed['versions'] as $name => $package) {
|
64 |
+
if (isset($package['type']) && $package['type'] === $type) {
|
65 |
+
$packagesByType[] = $name;
|
66 |
+
}
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
return $packagesByType;
|
71 |
+
}
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Checks whether the given package is installed
|
75 |
+
*
|
76 |
+
* This also returns true if the package name is provided or replaced by another package
|
77 |
+
*
|
78 |
+
* @param string $packageName
|
79 |
+
* @param bool $includeDevRequirements
|
80 |
+
* @return bool
|
81 |
+
*/
|
82 |
+
public static function isInstalled($packageName, $includeDevRequirements = true)
|
83 |
+
{
|
84 |
+
foreach (self::getInstalled() as $installed) {
|
85 |
+
if (isset($installed['versions'][$packageName])) {
|
86 |
+
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
|
87 |
+
}
|
88 |
+
}
|
89 |
+
|
90 |
+
return false;
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Checks whether the given package satisfies a version constraint
|
95 |
+
*
|
96 |
+
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
97 |
+
*
|
98 |
+
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
99 |
+
*
|
100 |
+
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
101 |
+
* @param string $packageName
|
102 |
+
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
103 |
+
* @return bool
|
104 |
+
*/
|
105 |
+
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
106 |
+
{
|
107 |
+
$constraint = $parser->parseConstraints($constraint);
|
108 |
+
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
109 |
+
|
110 |
+
return $provided->matches($constraint);
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Returns a version constraint representing all the range(s) which are installed for a given package
|
115 |
+
*
|
116 |
+
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
117 |
+
* whether a given version of a package is installed, and not just whether it exists
|
118 |
+
*
|
119 |
+
* @param string $packageName
|
120 |
+
* @return string Version constraint usable with composer/semver
|
121 |
+
*/
|
122 |
+
public static function getVersionRanges($packageName)
|
123 |
+
{
|
124 |
+
foreach (self::getInstalled() as $installed) {
|
125 |
+
if (!isset($installed['versions'][$packageName])) {
|
126 |
+
continue;
|
127 |
+
}
|
128 |
+
|
129 |
+
$ranges = array();
|
130 |
+
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
131 |
+
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
132 |
+
}
|
133 |
+
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
134 |
+
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
135 |
+
}
|
136 |
+
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
137 |
+
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
138 |
+
}
|
139 |
+
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
140 |
+
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
141 |
+
}
|
142 |
+
|
143 |
+
return implode(' || ', $ranges);
|
144 |
+
}
|
145 |
+
|
146 |
+
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
147 |
+
}
|
148 |
+
|
149 |
+
/**
|
150 |
+
* @param string $packageName
|
151 |
+
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
152 |
+
*/
|
153 |
+
public static function getVersion($packageName)
|
154 |
+
{
|
155 |
+
foreach (self::getInstalled() as $installed) {
|
156 |
+
if (!isset($installed['versions'][$packageName])) {
|
157 |
+
continue;
|
158 |
+
}
|
159 |
+
|
160 |
+
if (!isset($installed['versions'][$packageName]['version'])) {
|
161 |
+
return null;
|
162 |
+
}
|
163 |
+
|
164 |
+
return $installed['versions'][$packageName]['version'];
|
165 |
+
}
|
166 |
+
|
167 |
+
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* @param string $packageName
|
172 |
+
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
173 |
+
*/
|
174 |
+
public static function getPrettyVersion($packageName)
|
175 |
+
{
|
176 |
+
foreach (self::getInstalled() as $installed) {
|
177 |
+
if (!isset($installed['versions'][$packageName])) {
|
178 |
+
continue;
|
179 |
+
}
|
180 |
+
|
181 |
+
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
182 |
+
return null;
|
183 |
+
}
|
184 |
+
|
185 |
+
return $installed['versions'][$packageName]['pretty_version'];
|
186 |
+
}
|
187 |
+
|
188 |
+
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
189 |
+
}
|
190 |
+
|
191 |
+
/**
|
192 |
+
* @param string $packageName
|
193 |
+
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
194 |
+
*/
|
195 |
+
public static function getReference($packageName)
|
196 |
+
{
|
197 |
+
foreach (self::getInstalled() as $installed) {
|
198 |
+
if (!isset($installed['versions'][$packageName])) {
|
199 |
+
continue;
|
200 |
+
}
|
201 |
+
|
202 |
+
if (!isset($installed['versions'][$packageName]['reference'])) {
|
203 |
+
return null;
|
204 |
+
}
|
205 |
+
|
206 |
+
return $installed['versions'][$packageName]['reference'];
|
207 |
+
}
|
208 |
+
|
209 |
+
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
210 |
+
}
|
211 |
+
|
212 |
+
/**
|
213 |
+
* @param string $packageName
|
214 |
+
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
215 |
+
*/
|
216 |
+
public static function getInstallPath($packageName)
|
217 |
+
{
|
218 |
+
foreach (self::getInstalled() as $installed) {
|
219 |
+
if (!isset($installed['versions'][$packageName])) {
|
220 |
+
continue;
|
221 |
+
}
|
222 |
+
|
223 |
+
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
224 |
+
}
|
225 |
+
|
226 |
+
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
227 |
+
}
|
228 |
+
|
229 |
+
/**
|
230 |
+
* @return array
|
231 |
+
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
|
232 |
+
*/
|
233 |
+
public static function getRootPackage()
|
234 |
+
{
|
235 |
+
$installed = self::getInstalled();
|
236 |
+
|
237 |
+
return $installed[0]['root'];
|
238 |
+
}
|
239 |
+
|
240 |
+
/**
|
241 |
+
* Returns the raw installed.php data for custom implementations
|
242 |
+
*
|
243 |
+
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
244 |
+
* @return array[]
|
245 |
+
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
|
246 |
+
*/
|
247 |
+
public static function getRawData()
|
248 |
+
{
|
249 |
+
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
250 |
+
|
251 |
+
if (null === self::$installed) {
|
252 |
+
// only require the installed.php file if this file is loaded from its dumped location,
|
253 |
+
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
254 |
+
if (substr(__DIR__, -8, 1) !== 'C') {
|
255 |
+
self::$installed = include __DIR__ . '/installed.php';
|
256 |
+
} else {
|
257 |
+
self::$installed = array();
|
258 |
+
}
|
259 |
+
}
|
260 |
+
|
261 |
+
return self::$installed;
|
262 |
+
}
|
263 |
+
|
264 |
+
/**
|
265 |
+
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
266 |
+
*
|
267 |
+
* @return array[]
|
268 |
+
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
|
269 |
+
*/
|
270 |
+
public static function getAllRawData()
|
271 |
+
{
|
272 |
+
return self::getInstalled();
|
273 |
+
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* Lets you reload the static array from another file
|
277 |
+
*
|
278 |
+
* This is only useful for complex integrations in which a project needs to use
|
279 |
+
* this class but then also needs to execute another project's autoloader in process,
|
280 |
+
* and wants to ensure both projects have access to their version of installed.php.
|
281 |
+
*
|
282 |
+
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
283 |
+
* the data it needs from this class, then call reload() with
|
284 |
+
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
285 |
+
* the project in which it runs can then also use this class safely, without
|
286 |
+
* interference between PHPUnit's dependencies and the project's dependencies.
|
287 |
+
*
|
288 |
+
* @param array[] $data A vendor/composer/installed.php data set
|
289 |
+
* @return void
|
290 |
+
*
|
291 |
+
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
|
292 |
+
*/
|
293 |
+
public static function reload($data)
|
294 |
+
{
|
295 |
+
self::$installed = $data;
|
296 |
+
self::$installedByVendor = array();
|
297 |
+
}
|
298 |
+
|
299 |
+
/**
|
300 |
+
* @return array[]
|
301 |
+
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
|
302 |
+
*/
|
303 |
+
private static function getInstalled()
|
304 |
+
{
|
305 |
+
if (null === self::$canGetVendors) {
|
306 |
+
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
307 |
+
}
|
308 |
+
|
309 |
+
$installed = array();
|
310 |
+
|
311 |
+
if (self::$canGetVendors) {
|
312 |
+
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
313 |
+
if (isset(self::$installedByVendor[$vendorDir])) {
|
314 |
+
$installed[] = self::$installedByVendor[$vendorDir];
|
315 |
+
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
316 |
+
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
|
317 |
+
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
318 |
+
self::$installed = $installed[count($installed) - 1];
|
319 |
+
}
|
320 |
+
}
|
321 |
+
}
|
322 |
+
}
|
323 |
+
|
324 |
+
if (null === self::$installed) {
|
325 |
+
// only require the installed.php file if this file is loaded from its dumped location,
|
326 |
+
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
327 |
+
if (substr(__DIR__, -8, 1) !== 'C') {
|
328 |
+
self::$installed = require __DIR__ . '/installed.php';
|
329 |
+
} else {
|
330 |
+
self::$installed = array();
|
331 |
+
}
|
332 |
+
}
|
333 |
+
$installed[] = self::$installed;
|
334 |
+
|
335 |
+
return $installed;
|
336 |
+
}
|
337 |
}
|
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 |
|
@@ -24,15 +24,15 @@ class ComposerAutoloaderInit0a5c9cf66a2c48e36a98d940342789aa
|
|
24 |
|
25 |
require __DIR__ . '/platform_check.php';
|
26 |
|
27 |
-
spl_autoload_register(array('
|
28 |
-
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
29 |
-
spl_autoload_unregister(array('
|
30 |
|
31 |
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
32 |
if ($useStaticLoader) {
|
33 |
require __DIR__ . '/autoload_static.php';
|
34 |
|
35 |
-
call_user_func(\Composer\Autoload\
|
36 |
} else {
|
37 |
$map = require __DIR__ . '/autoload_namespaces.php';
|
38 |
foreach ($map as $namespace => $path) {
|
2 |
|
3 |
// autoload_real.php @generated by Composer
|
4 |
|
5 |
+
class ComposerAutoloaderInitde7d5bed3e120a58eb0e6fe4bc2b3a15
|
6 |
{
|
7 |
private static $loader;
|
8 |
|
24 |
|
25 |
require __DIR__ . '/platform_check.php';
|
26 |
|
27 |
+
spl_autoload_register(array('ComposerAutoloaderInitde7d5bed3e120a58eb0e6fe4bc2b3a15', 'loadClassLoader'), true, true);
|
28 |
+
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
|
29 |
+
spl_autoload_unregister(array('ComposerAutoloaderInitde7d5bed3e120a58eb0e6fe4bc2b3a15', 'loadClassLoader'));
|
30 |
|
31 |
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
32 |
if ($useStaticLoader) {
|
33 |
require __DIR__ . '/autoload_static.php';
|
34 |
|
35 |
+
call_user_func(\Composer\Autoload\ComposerStaticInitde7d5bed3e120a58eb0e6fe4bc2b3a15::getInitializer($loader));
|
36 |
} else {
|
37 |
$map = require __DIR__ . '/autoload_namespaces.php';
|
38 |
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' =>
|
@@ -43,9 +43,9 @@ class ComposerStaticInit0a5c9cf66a2c48e36a98d940342789aa
|
|
43 |
public static function getInitializer(ClassLoader $loader)
|
44 |
{
|
45 |
return \Closure::bind(function () use ($loader) {
|
46 |
-
$loader->prefixLengthsPsr4 =
|
47 |
-
$loader->prefixDirsPsr4 =
|
48 |
-
$loader->classMap =
|
49 |
|
50 |
}, null, ClassLoader::class);
|
51 |
}
|
4 |
|
5 |
namespace Composer\Autoload;
|
6 |
|
7 |
+
class ComposerStaticInitde7d5bed3e120a58eb0e6fe4bc2b3a15
|
8 |
{
|
9 |
public static $prefixLengthsPsr4 = array (
|
10 |
'S' =>
|
43 |
public static function getInitializer(ClassLoader $loader)
|
44 |
{
|
45 |
return \Closure::bind(function () use ($loader) {
|
46 |
+
$loader->prefixLengthsPsr4 = ComposerStaticInitde7d5bed3e120a58eb0e6fe4bc2b3a15::$prefixLengthsPsr4;
|
47 |
+
$loader->prefixDirsPsr4 = ComposerStaticInitde7d5bed3e120a58eb0e6fe4bc2b3a15::$prefixDirsPsr4;
|
48 |
+
$loader->classMap = ComposerStaticInitde7d5bed3e120a58eb0e6fe4bc2b3a15::$classMap;
|
49 |
|
50 |
}, null, ClassLoader::class);
|
51 |
}
|
vendor/composer/installed.json
CHANGED
@@ -2,17 +2,17 @@
|
|
2 |
"packages": [
|
3 |
{
|
4 |
"name": "composer/installers",
|
5 |
-
"version": "v1.
|
6 |
-
"version_normalized": "1.
|
7 |
"source": {
|
8 |
"type": "git",
|
9 |
"url": "https://github.com/composer/installers.git",
|
10 |
-
"reference": "
|
11 |
},
|
12 |
"dist": {
|
13 |
"type": "zip",
|
14 |
-
"url": "https://api.github.com/repos/composer/installers/zipball/
|
15 |
-
"reference": "
|
16 |
"shasum": ""
|
17 |
},
|
18 |
"require": {
|
@@ -30,7 +30,7 @@
|
|
30 |
"symfony/phpunit-bridge": "^4.2 || ^5",
|
31 |
"symfony/process": "^2.3"
|
32 |
},
|
33 |
-
"time": "2021-
|
34 |
"type": "composer-plugin",
|
35 |
"extra": {
|
36 |
"class": "Composer\\Installers\\Plugin",
|
@@ -113,6 +113,7 @@
|
|
113 |
"modx",
|
114 |
"moodle",
|
115 |
"osclass",
|
|
|
116 |
"phpbb",
|
117 |
"piwik",
|
118 |
"ppi",
|
@@ -135,7 +136,7 @@
|
|
135 |
],
|
136 |
"support": {
|
137 |
"issues": "https://github.com/composer/installers/issues",
|
138 |
-
"source": "https://github.com/composer/installers/tree/v1.
|
139 |
},
|
140 |
"funding": [
|
141 |
{
|
@@ -183,17 +184,17 @@
|
|
183 |
},
|
184 |
{
|
185 |
"name": "woocommerce/action-scheduler-job-framework",
|
186 |
-
"version": "
|
187 |
-
"version_normalized": "
|
188 |
"source": {
|
189 |
"type": "git",
|
190 |
"url": "https://github.com/woocommerce/action-scheduler-job-framework.git",
|
191 |
-
"reference": "
|
192 |
},
|
193 |
"dist": {
|
194 |
"type": "zip",
|
195 |
-
"url": "https://api.github.com/repos/woocommerce/action-scheduler-job-framework/zipball/
|
196 |
-
"reference": "
|
197 |
"shasum": ""
|
198 |
},
|
199 |
"require": {
|
@@ -202,7 +203,7 @@
|
|
202 |
"require-dev": {
|
203 |
"woocommerce/woocommerce-sniffs": "0.1.0"
|
204 |
},
|
205 |
-
"time": "2021-05-
|
206 |
"type": "library",
|
207 |
"installation-source": "dist",
|
208 |
"autoload": {
|
@@ -220,7 +221,7 @@
|
|
220 |
],
|
221 |
"description": "A job framework for Action Scheduler (actionscheduler.org)",
|
222 |
"support": {
|
223 |
-
"source": "https://github.com/woocommerce/action-scheduler-job-framework/tree/
|
224 |
"issues": "https://github.com/woocommerce/action-scheduler-job-framework/issues"
|
225 |
},
|
226 |
"install-path": "../woocommerce/action-scheduler-job-framework"
|
2 |
"packages": [
|
3 |
{
|
4 |
"name": "composer/installers",
|
5 |
+
"version": "v1.12.0",
|
6 |
+
"version_normalized": "1.12.0.0",
|
7 |
"source": {
|
8 |
"type": "git",
|
9 |
"url": "https://github.com/composer/installers.git",
|
10 |
+
"reference": "d20a64ed3c94748397ff5973488761b22f6d3f19"
|
11 |
},
|
12 |
"dist": {
|
13 |
"type": "zip",
|
14 |
+
"url": "https://api.github.com/repos/composer/installers/zipball/d20a64ed3c94748397ff5973488761b22f6d3f19",
|
15 |
+
"reference": "d20a64ed3c94748397ff5973488761b22f6d3f19",
|
16 |
"shasum": ""
|
17 |
},
|
18 |
"require": {
|
30 |
"symfony/phpunit-bridge": "^4.2 || ^5",
|
31 |
"symfony/process": "^2.3"
|
32 |
},
|
33 |
+
"time": "2021-09-13T08:19:44+00:00",
|
34 |
"type": "composer-plugin",
|
35 |
"extra": {
|
36 |
"class": "Composer\\Installers\\Plugin",
|
113 |
"modx",
|
114 |
"moodle",
|
115 |
"osclass",
|
116 |
+
"pantheon",
|
117 |
"phpbb",
|
118 |
"piwik",
|
119 |
"ppi",
|
136 |
],
|
137 |
"support": {
|
138 |
"issues": "https://github.com/composer/installers/issues",
|
139 |
+
"source": "https://github.com/composer/installers/tree/v1.12.0"
|
140 |
},
|
141 |
"funding": [
|
142 |
{
|
184 |
},
|
185 |
{
|
186 |
"name": "woocommerce/action-scheduler-job-framework",
|
187 |
+
"version": "2.0.0",
|
188 |
+
"version_normalized": "2.0.0.0",
|
189 |
"source": {
|
190 |
"type": "git",
|
191 |
"url": "https://github.com/woocommerce/action-scheduler-job-framework.git",
|
192 |
+
"reference": "b0b21b9cc87e476ba7f8817050b39274ea7d6732"
|
193 |
},
|
194 |
"dist": {
|
195 |
"type": "zip",
|
196 |
+
"url": "https://api.github.com/repos/woocommerce/action-scheduler-job-framework/zipball/b0b21b9cc87e476ba7f8817050b39274ea7d6732",
|
197 |
+
"reference": "b0b21b9cc87e476ba7f8817050b39274ea7d6732",
|
198 |
"shasum": ""
|
199 |
},
|
200 |
"require": {
|
203 |
"require-dev": {
|
204 |
"woocommerce/woocommerce-sniffs": "0.1.0"
|
205 |
},
|
206 |
+
"time": "2021-05-20T02:32:48+00:00",
|
207 |
"type": "library",
|
208 |
"installation-source": "dist",
|
209 |
"autoload": {
|
221 |
],
|
222 |
"description": "A job framework for Action Scheduler (actionscheduler.org)",
|
223 |
"support": {
|
224 |
+
"source": "https://github.com/woocommerce/action-scheduler-job-framework/tree/2.0.0",
|
225 |
"issues": "https://github.com/woocommerce/action-scheduler-job-framework/issues"
|
226 |
},
|
227 |
"install-path": "../woocommerce/action-scheduler-job-framework"
|
vendor/composer/installed.php
CHANGED
@@ -1,65 +1,62 @@
|
|
1 |
-
<?php return array
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
|
|
|
|
|
|
8 |
),
|
9 |
-
'
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
),
|
23 |
-
'facebookincubator/facebook-for-woocommerce' =>
|
24 |
-
array (
|
25 |
-
'pretty_version' => 'dev-release/2.6.5',
|
26 |
-
'version' => 'dev-release/2.6.5',
|
27 |
-
'aliases' =>
|
28 |
-
array (
|
29 |
-
),
|
30 |
-
'reference' => 'f4e8c6097d6622059705df6d7cbab9179609c055',
|
31 |
-
),
|
32 |
-
'roundcube/plugin-installer' =>
|
33 |
-
array (
|
34 |
-
'replaced' =>
|
35 |
-
array (
|
36 |
-
0 => '*',
|
37 |
-
),
|
38 |
-
),
|
39 |
-
'shama/baton' =>
|
40 |
-
array (
|
41 |
-
'replaced' =>
|
42 |
-
array (
|
43 |
-
0 => '*',
|
44 |
-
),
|
45 |
-
),
|
46 |
-
'skyverge/wc-plugin-framework' =>
|
47 |
-
array (
|
48 |
-
'pretty_version' => '5.10.0',
|
49 |
-
'version' => '5.10.0.0',
|
50 |
-
'aliases' =>
|
51 |
-
array (
|
52 |
-
),
|
53 |
-
'reference' => 'e230d7c40286854e49c0cafeec3398cbf2427a64',
|
54 |
-
),
|
55 |
-
'woocommerce/action-scheduler-job-framework' =>
|
56 |
-
array (
|
57 |
-
'pretty_version' => '1.0.0',
|
58 |
-
'version' => '1.0.0.0',
|
59 |
-
'aliases' =>
|
60 |
-
array (
|
61 |
-
),
|
62 |
-
'reference' => '718594e15d7ba2d56f8a37743bda6d7a8296e1c8',
|
63 |
-
),
|
64 |
-
),
|
65 |
);
|
1 |
+
<?php return array(
|
2 |
+
'root' => array(
|
3 |
+
'pretty_version' => 'dev-release/2.6.6',
|
4 |
+
'version' => 'dev-release/2.6.6',
|
5 |
+
'type' => 'wordpress-plugin',
|
6 |
+
'install_path' => __DIR__ . '/../../',
|
7 |
+
'aliases' => array(),
|
8 |
+
'reference' => '225d96525f5d3ac9330f597ba17af8041b24082a',
|
9 |
+
'name' => 'facebookincubator/facebook-for-woocommerce',
|
10 |
+
'dev' => false,
|
11 |
),
|
12 |
+
'versions' => array(
|
13 |
+
'composer/installers' => array(
|
14 |
+
'pretty_version' => 'v1.12.0',
|
15 |
+
'version' => '1.12.0.0',
|
16 |
+
'type' => 'composer-plugin',
|
17 |
+
'install_path' => __DIR__ . '/./installers',
|
18 |
+
'aliases' => array(),
|
19 |
+
'reference' => 'd20a64ed3c94748397ff5973488761b22f6d3f19',
|
20 |
+
'dev_requirement' => false,
|
21 |
+
),
|
22 |
+
'facebookincubator/facebook-for-woocommerce' => array(
|
23 |
+
'pretty_version' => 'dev-release/2.6.6',
|
24 |
+
'version' => 'dev-release/2.6.6',
|
25 |
+
'type' => 'wordpress-plugin',
|
26 |
+
'install_path' => __DIR__ . '/../../',
|
27 |
+
'aliases' => array(),
|
28 |
+
'reference' => '225d96525f5d3ac9330f597ba17af8041b24082a',
|
29 |
+
'dev_requirement' => false,
|
30 |
+
),
|
31 |
+
'roundcube/plugin-installer' => array(
|
32 |
+
'dev_requirement' => false,
|
33 |
+
'replaced' => array(
|
34 |
+
0 => '*',
|
35 |
+
),
|
36 |
+
),
|
37 |
+
'shama/baton' => array(
|
38 |
+
'dev_requirement' => false,
|
39 |
+
'replaced' => array(
|
40 |
+
0 => '*',
|
41 |
+
),
|
42 |
+
),
|
43 |
+
'skyverge/wc-plugin-framework' => array(
|
44 |
+
'pretty_version' => '5.10.0',
|
45 |
+
'version' => '5.10.0.0',
|
46 |
+
'type' => 'library',
|
47 |
+
'install_path' => __DIR__ . '/../skyverge/wc-plugin-framework',
|
48 |
+
'aliases' => array(),
|
49 |
+
'reference' => 'e230d7c40286854e49c0cafeec3398cbf2427a64',
|
50 |
+
'dev_requirement' => false,
|
51 |
+
),
|
52 |
+
'woocommerce/action-scheduler-job-framework' => array(
|
53 |
+
'pretty_version' => '2.0.0',
|
54 |
+
'version' => '2.0.0.0',
|
55 |
+
'type' => 'library',
|
56 |
+
'install_path' => __DIR__ . '/../woocommerce/action-scheduler-job-framework',
|
57 |
+
'aliases' => array(),
|
58 |
+
'reference' => 'b0b21b9cc87e476ba7f8817050b39274ea7d6732',
|
59 |
+
'dev_requirement' => false,
|
60 |
+
),
|
61 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
);
|
vendor/composer/installers/src/Composer/Installers/CakePHPInstaller.php
CHANGED
@@ -47,6 +47,7 @@ class CakePHPInstaller extends BaseInstaller
|
|
47 |
* @param string $matcher
|
48 |
* @param string $version
|
49 |
* @return bool
|
|
|
50 |
*/
|
51 |
protected function matchesCakeVersion($matcher, $version)
|
52 |
{
|
47 |
* @param string $matcher
|
48 |
* @param string $version
|
49 |
* @return bool
|
50 |
+
* @phpstan-param Constraint::STR_OP_* $matcher
|
51 |
*/
|
52 |
protected function matchesCakeVersion($matcher, $version)
|
53 |
{
|
vendor/composer/installers/src/Composer/Installers/Installer.php
CHANGED
@@ -91,6 +91,7 @@ class Installer extends LibraryInstaller
|
|
91 |
'phifty' => 'PhiftyInstaller',
|
92 |
'porto' => 'PortoInstaller',
|
93 |
'processwire' => 'ProcessWireInstaller',
|
|
|
94 |
'redaxo' => 'RedaxoInstaller',
|
95 |
'redaxo5' => 'Redaxo5Installer',
|
96 |
'reindex' => 'ReIndexInstaller',
|
91 |
'phifty' => 'PhiftyInstaller',
|
92 |
'porto' => 'PortoInstaller',
|
93 |
'processwire' => 'ProcessWireInstaller',
|
94 |
+
'quicksilver' => 'PantheonInstaller',
|
95 |
'redaxo' => 'RedaxoInstaller',
|
96 |
'redaxo5' => 'Redaxo5Installer',
|
97 |
'reindex' => 'ReIndexInstaller',
|
vendor/composer/installers/src/Composer/Installers/PantheonInstaller.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Composer\Installers;
|
4 |
+
|
5 |
+
class PantheonInstaller extends BaseInstaller
|
6 |
+
{
|
7 |
+
/** @var array<string, string> */
|
8 |
+
protected $locations = array(
|
9 |
+
'script' => 'web/private/scripts/quicksilver/{$name}',
|
10 |
+
'module' => 'web/private/scripts/quicksilver/{$name}',
|
11 |
+
);
|
12 |
+
}
|
vendor/woocommerce/action-scheduler-job-framework/CHANGELOG.md
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!-- For now we follow Gutenberg's package changelog format https://github.com/WordPress/gutenberg/tree/HEAD/packages#maintaining-changelogs. -->
|
2 |
+
|
3 |
+
## 2.0.0 (2021-05-19)
|
4 |
+
|
5 |
+
### Breaking Changes
|
6 |
+
|
7 |
+
- Removed `...AbstractChainedJob::filter_items_before_processing` method in favor of the more flexible `process_items` method ([#2](https://github.com/woocommerce/action-scheduler-job-framework/pull/2))
|
8 |
+
|
9 |
+
### New Feature
|
10 |
+
- Added `...AbstractChainedJob::process_items` method to give jobs more control over how the whole batch is processed ([#2](https://github.com/woocommerce/action-scheduler-job-framework/pull/2))
|
vendor/woocommerce/action-scheduler-job-framework/README.md
CHANGED
@@ -3,6 +3,36 @@
|
|
3 |
## Requirements
|
4 |
|
5 |
- PHP 7.0+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
|
7 |
## Chained Jobs
|
8 |
|
3 |
## Requirements
|
4 |
|
5 |
- PHP 7.0+
|
6 |
+
- [Jetpack Autoloader](https://github.com/Automattic/jetpack-autoloader) - Required to ensure the latest version of the framework is used in case multiple plugins have it as a dependency
|
7 |
+
|
8 |
+
|
9 |
+
## Versioning & breaking changes
|
10 |
+
|
11 |
+
This package follows [Semver](https://semver.org/) for versioning.
|
12 |
+
|
13 |
+
This framework may receive breaking changes at the moment while it is only used in the [Facebook for WooCommerce](https://github.com/woocommerce/facebook-for-woocommerce) plugin.
|
14 |
+
However, once we use it in another plugin we will need to reject all breaking changes.
|
15 |
+
|
16 |
+
## Installation
|
17 |
+
|
18 |
+
The framework should be installed via [Composer](https://getcomposer.org/).
|
19 |
+
|
20 |
+
1. Add the following to your project's `composer.json` file:
|
21 |
+
```json
|
22 |
+
{
|
23 |
+
"repositories": [
|
24 |
+
{
|
25 |
+
"type": "vcs",
|
26 |
+
"url": "https://github.com/woocommerce/action-scheduler-job-framework"
|
27 |
+
}
|
28 |
+
],
|
29 |
+
"require": {
|
30 |
+
"woocommerce/action-scheduler-job-framework": "1.0.0"
|
31 |
+
}
|
32 |
+
}
|
33 |
+
```
|
34 |
+
|
35 |
+
2. Then run `composer update`
|
36 |
|
37 |
## Chained Jobs
|
38 |
|
vendor/woocommerce/action-scheduler-job-framework/src/AbstractChainedJob.php
CHANGED
@@ -138,11 +138,7 @@ abstract class AbstractChainedJob extends AbstractJob implements ChainedJobInter
|
|
138 |
// No more items to process so end the job chain
|
139 |
$this->queue_end( $args );
|
140 |
} else {
|
141 |
-
$
|
142 |
-
|
143 |
-
foreach ( $items as $item ) {
|
144 |
-
$this->process_item( $item, $args );
|
145 |
-
}
|
146 |
|
147 |
// If there were items, queue another batch.
|
148 |
$this->queue_batch( $batch_number + 1, $args );
|
@@ -150,16 +146,19 @@ abstract class AbstractChainedJob extends AbstractJob implements ChainedJobInter
|
|
150 |
}
|
151 |
|
152 |
/**
|
153 |
-
*
|
154 |
*
|
155 |
-
*
|
156 |
*
|
157 |
-
* @param array $items
|
|
|
158 |
*
|
159 |
-
* @
|
160 |
*/
|
161 |
-
protected function
|
162 |
-
|
|
|
|
|
163 |
}
|
164 |
|
165 |
/**
|
138 |
// No more items to process so end the job chain
|
139 |
$this->queue_end( $args );
|
140 |
} else {
|
141 |
+
$this->process_items( $items, $args );
|
|
|
|
|
|
|
|
|
142 |
|
143 |
// If there were items, queue another batch.
|
144 |
$this->queue_batch( $batch_number + 1, $args );
|
146 |
}
|
147 |
|
148 |
/**
|
149 |
+
* Processes a batch of items.
|
150 |
*
|
151 |
+
* @since 1.1.0
|
152 |
*
|
153 |
+
* @param array $items The items of the current batch.
|
154 |
+
* @param array $args The args for the job.
|
155 |
*
|
156 |
+
* @throws Exception On error. The failure will be logged by Action Scheduler and the job chain will stop.
|
157 |
*/
|
158 |
+
protected function process_items( array $items, array $args ) {
|
159 |
+
foreach ( $items as $item ) {
|
160 |
+
$this->process_item( $item, $args );
|
161 |
+
}
|
162 |
}
|
163 |
|
164 |
/**
|