From 24aa179ed4cb2e3dfd986114e557b3c6a30d976e Mon Sep 17 00:00:00 2001 From: Noah Ostrowski Date: Thu, 13 Mar 2025 13:30:57 -0700 Subject: [PATCH 01/14] Adding function on Connection to fetch CPI ID. Updating AbstractFeed to only schedule/regenerate feed if CPI ID is set. Updating how we fetch CMS ID in R&R feed upload logic. --- includes/Feed/AbstractFeed.php | 15 +++++++++++++-- includes/Feed/FeedUploadUtils.php | 2 +- includes/Handlers/Connection.php | 14 ++++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/includes/Feed/AbstractFeed.php b/includes/Feed/AbstractFeed.php index 37951026c..ca04c944f 100644 --- a/includes/Feed/AbstractFeed.php +++ b/includes/Feed/AbstractFeed.php @@ -96,6 +96,12 @@ abstract class AbstractFeed { * @since 3.5.0 */ public function schedule_feed_generation(): void { + // If the Commerce Partner Integration ID isn't set then don't schedule feed generation + $cpi_id = facebook_for_woocommerce()->get_connection_handler()->get_commerce_partner_integration_id(); + if ( '' === $cpi_id ) { + return; + } + $schedule_action_hook_name = self::GENERATE_FEED_ACTION . $this->data_stream_name; if ( ! as_next_scheduled_action( $schedule_action_hook_name ) ) { as_schedule_recurring_action( @@ -116,8 +122,13 @@ public function schedule_feed_generation(): void { * @since 3.5.0 */ public function regenerate_feed(): void { - // Maybe use new ( experimental ), feed generation framework. - if ( \WC_Facebookcommerce::instance()->get_integration()->is_new_style_feed_generation_enabled() ) { + // If the Commerce Partner Integration ID isn't set then don't generate the feed + $cpi_id = facebook_for_woocommerce()->get_connection_handler()->get_commerce_partner_integration_id(); + if ( '' === $cpi_id ) { + return; + } + + if ( facebook_for_woocommerce()->get_integration()->is_new_style_feed_generation_enabled() ) { $this->feed_generator->queue_start(); } else { $this->feed_handler->generate_feed_file(); diff --git a/includes/Feed/FeedUploadUtils.php b/includes/Feed/FeedUploadUtils.php index a3a46f8ab..523d0b0cd 100644 --- a/includes/Feed/FeedUploadUtils.php +++ b/includes/Feed/FeedUploadUtils.php @@ -21,7 +21,7 @@ public static function get_ratings_and_reviews_data( array $query_args ): array $reviews_data = array(); $store_name = get_bloginfo( 'name' ); - $store_id = get_option( 'wc_facebook_commerce_merchant_settings_id', '' ); + $store_id = facebook_for_woocommerce()->get_connection_handler()->get_commerce_partner_integration_id(); $store_urls = [ wc_get_page_permalink( 'shop' ) ]; foreach ( $comments as $comment ) { diff --git a/includes/Handlers/Connection.php b/includes/Handlers/Connection.php index 39a4e2114..2e31df427 100644 --- a/includes/Handlers/Connection.php +++ b/includes/Handlers/Connection.php @@ -97,6 +97,9 @@ class Connection { /** @var string the Commerce merchant settings ID option name */ const OPTION_COMMERCE_MERCHANT_SETTINGS_ID = 'wc_facebook_commerce_merchant_settings_id'; + /** @var string the Commerce Partner Integration ID option name */ + const OPTION_COMMERCE_PARTNER_INTEGRATION_ID = 'wc_facebook_commerce_partner_integration_id'; + /** @var string|null the generated external merchant settings ID */ private $external_business_id; @@ -793,6 +796,17 @@ public function get_commerce_merchant_settings_id() { return get_option( self::OPTION_COMMERCE_MERCHANT_SETTINGS_ID, '' ); } + /** + * Gets Commerce Partner Integration ID value. + * + * @since 3.5.0 + * + * @return string + */ + public function get_commerce_partner_integration_id() { + return get_option( self::OPTION_COMMERCE_PARTNER_INTEGRATION_ID, '' ); + } + /** * Gets the proxy URL. From 95972b7954c2acd00f309a99fae41cfeac9aa31d Mon Sep 17 00:00:00 2001 From: Noah Ostrowski Date: Thu, 13 Mar 2025 16:52:29 -0700 Subject: [PATCH 02/14] Adding newline --- includes/Handlers/Connection.php | 1 + 1 file changed, 1 insertion(+) diff --git a/includes/Handlers/Connection.php b/includes/Handlers/Connection.php index 2e31df427..8bd3b211b 100644 --- a/includes/Handlers/Connection.php +++ b/includes/Handlers/Connection.php @@ -796,6 +796,7 @@ public function get_commerce_merchant_settings_id() { return get_option( self::OPTION_COMMERCE_MERCHANT_SETTINGS_ID, '' ); } + /** * Gets Commerce Partner Integration ID value. * From 6cb3de064da552de88bb487a2067357d527a02db Mon Sep 17 00:00:00 2001 From: Noah Ostrowski Date: Fri, 14 Mar 2025 10:32:45 -0700 Subject: [PATCH 03/14] Creating funciton for should skip logic. --- includes/Feed/AbstractFeed.php | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/includes/Feed/AbstractFeed.php b/includes/Feed/AbstractFeed.php index ca04c944f..cff2a7d96 100644 --- a/includes/Feed/AbstractFeed.php +++ b/includes/Feed/AbstractFeed.php @@ -96,9 +96,7 @@ abstract class AbstractFeed { * @since 3.5.0 */ public function schedule_feed_generation(): void { - // If the Commerce Partner Integration ID isn't set then don't schedule feed generation - $cpi_id = facebook_for_woocommerce()->get_connection_handler()->get_commerce_partner_integration_id(); - if ( '' === $cpi_id ) { + if ( $this->should_skip_feed() ) { return; } @@ -122,9 +120,7 @@ public function schedule_feed_generation(): void { * @since 3.5.0 */ public function regenerate_feed(): void { - // If the Commerce Partner Integration ID isn't set then don't generate the feed - $cpi_id = facebook_for_woocommerce()->get_connection_handler()->get_commerce_partner_integration_id(); - if ( '' === $cpi_id ) { + if ( $this->should_skip_feed() ) { return; } @@ -135,6 +131,19 @@ public function regenerate_feed(): void { } } + /** + * The feed should be skipped if there isn't a Commerce Partner Integration ID set as the ID is required for + * calls to the GraphCommercePartnerIntegrationFileUpdatePost endpoint. + * Overwrite this function if your feed upload uses a different endpoint with different requirements. + * + * @since 3.5.0 + */ + public function should_skip_feed(): bool { + $cpi_id = facebook_for_woocommerce()->get_connection_handler()->get_commerce_partner_integration_id(); + + return empty( $cpi_id ); + } + /** * Trigger the upload flow * Once feed regenerated, trigger upload via create_upload API From 306ed69f69d3fe0d83cc2a6f8d5eda37ab8e788f Mon Sep 17 00:00:00 2001 From: Noah Ostrowski Date: Wed, 19 Mar 2025 10:34:28 -0700 Subject: [PATCH 04/14] Using get_commerce_partner_integration_id --- includes/Feed/AbstractFeed.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/Feed/AbstractFeed.php b/includes/Feed/AbstractFeed.php index cff2a7d96..702d39684 100644 --- a/includes/Feed/AbstractFeed.php +++ b/includes/Feed/AbstractFeed.php @@ -160,7 +160,7 @@ public function send_request_to_upload_feed(): void { ); try { - $cpi_id = get_option( 'wc_facebook_commerce_partner_integration_id', '' ); + $cpi_id = facebook_for_woocommerce()->get_connection_handler()->get_commerce_partner_integration_id(); facebook_for_woocommerce()-> get_api()-> create_common_data_feed_upload( $cpi_id, $data ); From 553487393924cb3a5c09d4d33cc6d390c1afa28a Mon Sep 17 00:00:00 2001 From: Noah Ostrowski Date: Wed, 19 Mar 2025 11:27:31 -0700 Subject: [PATCH 05/14] Updating call to get_commerce_merchant_settings_id --- includes/Feed/FeedUploadUtils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/Feed/FeedUploadUtils.php b/includes/Feed/FeedUploadUtils.php index 523d0b0cd..670f1f384 100644 --- a/includes/Feed/FeedUploadUtils.php +++ b/includes/Feed/FeedUploadUtils.php @@ -21,7 +21,7 @@ public static function get_ratings_and_reviews_data( array $query_args ): array $reviews_data = array(); $store_name = get_bloginfo( 'name' ); - $store_id = facebook_for_woocommerce()->get_connection_handler()->get_commerce_partner_integration_id(); + $store_id = facebook_for_woocommerce()->get_connection_handler()->get_commerce_merchant_settings_id(); $store_urls = [ wc_get_page_permalink( 'shop' ) ]; foreach ( $comments as $comment ) { From 3e9ae80150f58ec2562ff072ea01382d76d41056 Mon Sep 17 00:00:00 2001 From: Noah Ostrowski Date: Fri, 21 Mar 2025 13:01:27 -0700 Subject: [PATCH 06/14] Adding some logging --- includes/Feed/AbstractFeed.php | 29 ++++-- includes/Feed/CsvFeedFileWriter.php | 13 ++- includes/Feed/FeedUploadUtils.php | 137 ++++++++++++++++------------ 3 files changed, 115 insertions(+), 64 deletions(-) diff --git a/includes/Feed/AbstractFeed.php b/includes/Feed/AbstractFeed.php index b06538b53..2892d1024 100644 --- a/includes/Feed/AbstractFeed.php +++ b/includes/Feed/AbstractFeed.php @@ -171,9 +171,17 @@ public function send_request_to_upload_feed(): void { facebook_for_woocommerce()-> get_api()-> create_common_data_feed_upload( $cpi_id, $data ); - } catch ( Exception $e ) { - // Log the error and continue. - \WC_Facebookcommerce_Utils::log( "{$name} feed: Failed to create feed upload request: " . $e->getMessage() ); + } catch ( Exception $exception ) { + \WC_Facebookcommerce_Utils::logExceptionImmediatelyToMeta( + $exception, + [ + 'event' => 'feed_upload', + 'event_type' => 'send_request_to_upload_feed', + 'extra_data' => [ + 'feed_type' => $name, + ], + ] + ); } } @@ -264,16 +272,25 @@ public function handle_feed_data_request(): void { // fpassthru might be disabled in some hosts (like Flywheel). // phpcs:ignore if ( \WC_Facebookcommerce_Utils::is_fpassthru_disabled() || ! @fpassthru( $file ) ) { - \WC_Facebookcommerce_Utils::log( "{$name} feed: fpassthru is disabled: getting file contents" ); + \WC_Facebookcommerce_Utils::log( "{$name} feed: fpassthru is disabled: getting file contents." ); //phpcs:ignore $contents = @stream_get_contents( $file ); if ( ! $contents ) { - throw new PluginException( 'Could not get feed file contents.', 500 ); + throw new PluginException( "{$name} feed: Could not get feed file contents.", 500 ); } echo $contents; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } } catch ( \Exception $exception ) { - \WC_Facebookcommerce_Utils::log( "{$name} feed: Could not serve feed. " . $exception->getMessage() . ' (' . $exception->getCode() . ')' ); + \WC_Facebookcommerce_Utils::logExceptionImmediatelyToMeta( + $exception, + [ + 'event' => 'feed_upload', + 'event_type' => 'handle_feed_data_request', + 'extra_data' => [ + 'feed_type' => $name, + ], + ] + ); status_header( $exception->getCode() ); } exit; diff --git a/includes/Feed/CsvFeedFileWriter.php b/includes/Feed/CsvFeedFileWriter.php index e97771ddc..db57cdceb 100644 --- a/includes/Feed/CsvFeedFileWriter.php +++ b/includes/Feed/CsvFeedFileWriter.php @@ -109,8 +109,17 @@ public function write_feed_file( array $data ): void { // Step 3: Rename temporary feed file to final feed file. $this->promote_temp_file(); - } catch ( PluginException $e ) { - WC_Facebookcommerce_Utils::logExceptionImmediatelyToMeta( $e ); + } catch ( PluginException $exception ) { + \WC_Facebookcommerce_Utils::logExceptionImmediatelyToMeta( + $exception, + [ + 'event' => 'feed_upload', + 'event_type' => 'csv_write_feed_file', + 'extra_data' => [ + 'feed_type' => $this->feed_name, + ], + ] + ); // Close the temporary file if it is still open. if ( ! empty( $temp_feed_file ) && is_resource( $temp_feed_file ) ) { fclose( $temp_feed_file ); // phpcs:ignore diff --git a/includes/Feed/FeedUploadUtils.php b/includes/Feed/FeedUploadUtils.php index c3b7ea7ef..66220e33d 100644 --- a/includes/Feed/FeedUploadUtils.php +++ b/includes/Feed/FeedUploadUtils.php @@ -18,72 +18,97 @@ * @since 3.5.0 */ class FeedUploadUtils { - const VALUE_TYPE_PERCENTAGE = 'PERCENTAGE'; - const VALUE_TYPE_FIXED_AMOUNT = 'FIXED_AMOUNT'; - const TARGET_TYPE_SHIPPING = 'SHIPPING'; - const TARGET_TYPE_LINE_ITEM = 'LINE_ITEM'; - const TARGET_GRANULARITY_ORDER_LEVEL = 'ORDER_LEVEL'; - const TARGET_GRANULARITY_ITEM_LEVEL = 'ITEM_LEVEL'; - const TARGET_SELECTION_ENTIRE_CATALOG = 'ALL_CATALOG_PRODUCTS'; - const TARGET_SELECTION_SPECIFIC_PRODUCTS = 'SPECIFIC_PRODUCTS'; - const APPLICATION_TYPE_BUYER_APPLIED = 'BUYER_APPLIED'; - const PROMO_SYNC_LOGGING_FLOW_NAME = 'promotion_feed_sync'; + const VALUE_TYPE_PERCENTAGE = 'PERCENTAGE'; + const VALUE_TYPE_FIXED_AMOUNT = 'FIXED_AMOUNT'; + const TARGET_TYPE_SHIPPING = 'SHIPPING'; + const TARGET_TYPE_LINE_ITEM = 'LINE_ITEM'; + const TARGET_GRANULARITY_ORDER_LEVEL = 'ORDER_LEVEL'; + const TARGET_GRANULARITY_ITEM_LEVEL = 'ITEM_LEVEL'; + const TARGET_SELECTION_ENTIRE_CATALOG = 'ALL_CATALOG_PRODUCTS'; + const TARGET_SELECTION_SPECIFIC_PRODUCTS = 'SPECIFIC_PRODUCTS'; + const APPLICATION_TYPE_BUYER_APPLIED = 'BUYER_APPLIED'; + const PROMO_SYNC_LOGGING_FLOW_NAME = 'promotion_feed_sync'; + const RATINGS_AND_REVIEWS_SYNC_LOGGING_FLOW_NAME = 'ratings_and_reviews_feed_sync'; public static function get_ratings_and_reviews_data( array $query_args ): array { - $comments = get_comments( $query_args ); - $reviews_data = array(); + try { + $comments = get_comments( $query_args ); + $reviews_data = array(); - $store_name = get_bloginfo( 'name' ); - $store_id = facebook_for_woocommerce()->get_connection_handler()->get_commerce_merchant_settings_id(); - $store_urls = [ wc_get_page_permalink( 'shop' ) ]; + $store_name = get_bloginfo( 'name' ); + $store_id = facebook_for_woocommerce()->get_connection_handler()->get_commerce_merchant_settings_id(); + $store_urls = [ wc_get_page_permalink( 'shop' ) ]; - foreach ( $comments as $comment ) { - try { - $post_type = get_post_type( $comment->comment_post_ID ); - if ( 'product' !== $post_type ) { - continue; - } + foreach ( $comments as $comment ) { + try { + $post_type = get_post_type( $comment->comment_post_ID ); + if ( 'product' !== $post_type ) { + continue; + } - $rating = get_comment_meta( $comment->comment_ID, 'rating', true ); - if ( ! is_numeric( $rating ) ) { - continue; - } + $rating = get_comment_meta( $comment->comment_ID, 'rating', true ); + if ( ! is_numeric( $rating ) ) { + continue; + } - $reviewer_id = $comment->user_id; - // If reviewer_id is 0 then the reviewer is a logged-out user - $reviewer_is_anonymous = '0' === $reviewer_id ? 'true' : 'false'; + $reviewer_id = $comment->user_id; + // If reviewer_id is 0 then the reviewer is a logged-out user + $reviewer_is_anonymous = '0' === $reviewer_id ? 'true' : 'false'; - $product = wc_get_product( $comment->comment_post_ID ); - if ( null === $product ) { + $product = wc_get_product( $comment->comment_post_ID ); + if ( null === $product ) { + continue; + } + $product_name = $product->get_name(); + $product_url = $product->get_permalink(); + $product_skus = [ $product->get_sku() ]; + + $reviews_data[] = array( + 'aggregator' => 'woocommerce', + 'store.name' => $store_name, + 'store.id' => $store_id, + 'store.storeUrls' => "['" . implode( "','", $store_urls ) . "']", + 'review_id' => $comment->comment_ID, + 'rating' => intval( $rating ), + 'title' => null, + 'content' => $comment->comment_content, + 'created_at' => $comment->comment_date, + 'reviewer.name' => $comment->comment_author, + 'reviewer.reviewerID' => $reviewer_id, + 'reviewer.isAnonymous' => $reviewer_is_anonymous, + 'product.name' => $product_name, + 'product.url' => $product_url, + 'product.productIdentifiers.skus' => "['" . implode( "','", $product_skus ) . "']", + ); + } catch ( \Exception $e ) { + \WC_Facebookcommerce_Utils::logTelemetryToMeta( + 'Exception while trying to map product review data for feed', + array( + 'flow_name' => self::RATINGS_AND_REVIEWS_SYNC_LOGGING_FLOW_NAME, + 'flow_step' => 'map_ratings_and_reviews_data', + 'extra_data' => [ + 'exception_message' => $e->getMessage(), + ], + ) + ); continue; } - $product_name = $product->get_name(); - $product_url = $product->get_permalink(); - $product_skus = [ $product->get_sku() ]; - - $reviews_data[] = array( - 'aggregator' => 'woocommerce', - 'store.name' => $store_name, - 'store.id' => $store_id, - 'store.storeUrls' => "['" . implode( "','", $store_urls ) . "']", - 'review_id' => $comment->comment_ID, - 'rating' => intval( $rating ), - 'title' => null, - 'content' => $comment->comment_content, - 'created_at' => $comment->comment_date, - 'reviewer.name' => $comment->comment_author, - 'reviewer.reviewerID' => $reviewer_id, - 'reviewer.isAnonymous' => $reviewer_is_anonymous, - 'product.name' => $product_name, - 'product.url' => $product_url, - 'product.productIdentifiers.skus' => "['" . implode( "','", $product_skus ) . "']", - ); - } catch ( \Exception $e ) { - continue; } - } - return $reviews_data; + return $reviews_data; + } catch ( \Exception $exception ) { + \WC_Facebookcommerce_Utils::logExceptionImmediatelyToMeta( + $exception, + [ + 'event' => self::RATINGS_AND_REVIEWS_SYNC_LOGGING_FLOW_NAME, + 'event_type' => 'get_ratings_and_reviews_data', + 'extra_data' => [ + 'query_args' => wp_json_encode( $query_args ), + ], + ] + ); + throw $exception; + } } /** @@ -124,7 +149,7 @@ public static function get_coupons_data( array $query_args ): array { 'Unknown discount type encountered during feed processing', array( 'promotion_id' => $coupon_post->ID, - 'extra_data' => array( 'discount_type' => $woo_discount_type ), + 'extra_data' => [ 'discount_type' => $woo_discount_type ], 'flow_name' => self::PROMO_SYNC_LOGGING_FLOW_NAME, 'flow_step' => 'map_discount_type', ) From 0d5895946942410972f03271dc29a77a5d60a98c Mon Sep 17 00:00:00 2001 From: Noah Ostrowski Date: Fri, 21 Mar 2025 16:25:31 -0700 Subject: [PATCH 07/14] Adding test cases for AbstractFeed --- tests/Unit/Feed/AbstractFeedTest.php | 68 ++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 tests/Unit/Feed/AbstractFeedTest.php diff --git a/tests/Unit/Feed/AbstractFeedTest.php b/tests/Unit/Feed/AbstractFeedTest.php new file mode 100644 index 000000000..af843f037 --- /dev/null +++ b/tests/Unit/Feed/AbstractFeedTest.php @@ -0,0 +1,68 @@ +init( + $file_writer, + $feed_handler, + $feed_generator, + ); + } + + protected static function get_data_stream_name(): string { + return 'test'; + } + + protected static function get_feed_type(): string { + return 'TEST_FEED'; + } + + protected static function get_feed_gen_interval(): int { + return HOUR_IN_SECONDS; + } +} + +class AbstractFeedTest extends WP_UnitTestCase { + /** + * The test feed class. + * + * @var AbstractFeed + * @since 3.5.0 + */ + protected AbstractFeed $feed; + + public function setUp(): void { + parent::setUp(); + $file_writer = $this->createMock( FeedFileWriter::class ); + $feed_handler = $this->createMock( AbstractFeedHandler::class ); + $feed_generator = $this->createMock( FeedGenerator::class ); + $this->feed = new TestFeed($file_writer, $feed_handler, $feed_generator); + } + + public function testShouldSkipFeed() { + update_option( 'wc_facebook_commerce_partner_integration_id', '1841465350002849' ); + $this->assertFalse( $this->feed->should_skip_feed(), 'Feed should not be skipped when CPI ID is not empty.' ); + update_option( 'wc_facebook_commerce_partner_integration_id', '' ); + $this->assertTrue( $this->feed->should_skip_feed(), 'Feed should be skipped when CPI ID is empty.' ); + } + + public function testGetFeedSecret() { + $secret_option_name = 'wc_facebook_feed_url_secret_test'; + $this->assertEmpty(get_option($secret_option_name, ''), 'Secret should not be set yet.'); + $secret = $this->feed->get_feed_secret(); + $this->assertNotEmpty($secret, 'When secret is not set yet one should be generated.'); + $this->assertEquals($secret, get_option($secret_option_name, ''), 'Secret should be set.'); + } +} From 789819324663ce0a7783d6265fd6d505c1dff4b8 Mon Sep 17 00:00:00 2001 From: Noah Ostrowski Date: Fri, 21 Mar 2025 17:02:56 -0700 Subject: [PATCH 08/14] Updating logging values --- includes/Feed/AbstractFeed.php | 2 +- includes/Feed/CsvFeedFileWriter.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/Feed/AbstractFeed.php b/includes/Feed/AbstractFeed.php index 2892d1024..ad8be14e0 100644 --- a/includes/Feed/AbstractFeed.php +++ b/includes/Feed/AbstractFeed.php @@ -287,7 +287,7 @@ public function handle_feed_data_request(): void { 'event' => 'feed_upload', 'event_type' => 'handle_feed_data_request', 'extra_data' => [ - 'feed_type' => $name, + 'feed_name' => $name, ], ] ); diff --git a/includes/Feed/CsvFeedFileWriter.php b/includes/Feed/CsvFeedFileWriter.php index db57cdceb..ace09a2ea 100644 --- a/includes/Feed/CsvFeedFileWriter.php +++ b/includes/Feed/CsvFeedFileWriter.php @@ -116,7 +116,7 @@ public function write_feed_file( array $data ): void { 'event' => 'feed_upload', 'event_type' => 'csv_write_feed_file', 'extra_data' => [ - 'feed_type' => $this->feed_name, + 'feed_name' => $this->feed_name, ], ] ); From c2ed3a9c7ad36e59590b5c1880aeca8e8f57baf9 Mon Sep 17 00:00:00 2001 From: Noah Ostrowski Date: Fri, 21 Mar 2025 17:05:25 -0700 Subject: [PATCH 09/14] feed_type to feed_name --- includes/Feed/AbstractFeed.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/Feed/AbstractFeed.php b/includes/Feed/AbstractFeed.php index ad8be14e0..a451a090a 100644 --- a/includes/Feed/AbstractFeed.php +++ b/includes/Feed/AbstractFeed.php @@ -178,7 +178,7 @@ public function send_request_to_upload_feed(): void { 'event' => 'feed_upload', 'event_type' => 'send_request_to_upload_feed', 'extra_data' => [ - 'feed_type' => $name, + 'feed_name' => $name, ], ] ); From 67acf5ce9f1da1325105551e8ed17ad709415ad3 Mon Sep 17 00:00:00 2001 From: Noah Ostrowski Date: Fri, 21 Mar 2025 17:11:27 -0700 Subject: [PATCH 10/14] Adding some additional logging fields --- includes/Feed/AbstractFeed.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/includes/Feed/AbstractFeed.php b/includes/Feed/AbstractFeed.php index a451a090a..7347ed84c 100644 --- a/includes/Feed/AbstractFeed.php +++ b/includes/Feed/AbstractFeed.php @@ -179,6 +179,7 @@ public function send_request_to_upload_feed(): void { 'event_type' => 'send_request_to_upload_feed', 'extra_data' => [ 'feed_name' => $name, + 'data' => wp_json_encode( $data ), ], ] ); @@ -288,6 +289,7 @@ public function handle_feed_data_request(): void { 'event_type' => 'handle_feed_data_request', 'extra_data' => [ 'feed_name' => $name, + 'file_path' => $file_path, ], ] ); From b00d9829fdc9a9a95b997827371db6fc356e2ab2 Mon Sep 17 00:00:00 2001 From: Noah Ostrowski Date: Fri, 21 Mar 2025 17:27:21 -0700 Subject: [PATCH 11/14] Adding more test cases --- tests/Unit/Feed/AbstractFeedTest.php | 41 ++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tests/Unit/Feed/AbstractFeedTest.php b/tests/Unit/Feed/AbstractFeedTest.php index af843f037..1f93d071c 100644 --- a/tests/Unit/Feed/AbstractFeedTest.php +++ b/tests/Unit/Feed/AbstractFeedTest.php @@ -11,6 +11,7 @@ namespace WooCommerce\Facebook\Feed; use WP_UnitTestCase; +use WooCommerce\Facebook\Utilities\Heartbeat; class TestFeed extends AbstractFeed { public function __construct(FeedFileWriter $file_writer, AbstractFeedHandler $feed_handler, FeedGenerator $feed_generator) { @@ -32,6 +33,10 @@ protected static function get_feed_type(): string { protected static function get_feed_gen_interval(): int { return HOUR_IN_SECONDS; } + + protected static function get_feed_gen_scheduling_interval(): string { + return Heartbeat::EVERY_5_MINUTES; + } } class AbstractFeedTest extends WP_UnitTestCase { @@ -65,4 +70,40 @@ public function testGetFeedSecret() { $this->assertNotEmpty($secret, 'When secret is not set yet one should be generated.'); $this->assertEquals($secret, get_option($secret_option_name, ''), 'Secret should be set.'); } + + public function testGetDataStreamName() { + $reflection = new \ReflectionClass($this->feed); + $method = $reflection->getMethod('get_data_stream_name'); + $method->setAccessible(true); + + $data_stream_name = $method->invoke($this->feed); + $this->assertEquals('test', $data_stream_name, 'The data stream name should be "test".'); + } + + public function testGetFeedType() { + $reflection = new \ReflectionClass($this->feed); + $method = $reflection->getMethod('get_feed_type'); + $method->setAccessible(true); + + $feed_type = $method->invoke($this->feed); + $this->assertEquals('TEST_FEED', $feed_type, 'The feed type should be "TEST_FEED".'); + } + + public function testGetFeedGenInterval() { + $reflection = new \ReflectionClass($this->feed); + $method = $reflection->getMethod('get_feed_gen_interval'); + $method->setAccessible(true); + + $feed_gen_interval = $method->invoke($this->feed); + $this->assertEquals(HOUR_IN_SECONDS, $feed_gen_interval, 'The feed gen interval should be HOUR_IN_SECONDS.'); + } + + public function testGetFeedGenSchedulingInterval() { + $reflection = new \ReflectionClass($this->feed); + $method = $reflection->getMethod('get_feed_gen_scheduling_interval'); + $method->setAccessible(true); + + $feed_gen_interval = $method->invoke($this->feed); + $this->assertEquals(Heartbeat::EVERY_5_MINUTES, $feed_gen_interval, 'The feed gen scheduling interval should be Heartbeat::EVERY_5_MINUTES.'); + } } From e98d73bb7e2d9b92316c72f9c917bfa95c32a0e5 Mon Sep 17 00:00:00 2001 From: Noah Ostrowski Date: Fri, 21 Mar 2025 17:38:04 -0700 Subject: [PATCH 12/14] Updating variable name --- tests/Unit/Feed/AbstractFeedTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Unit/Feed/AbstractFeedTest.php b/tests/Unit/Feed/AbstractFeedTest.php index 1f93d071c..2eedf854a 100644 --- a/tests/Unit/Feed/AbstractFeedTest.php +++ b/tests/Unit/Feed/AbstractFeedTest.php @@ -103,7 +103,7 @@ public function testGetFeedGenSchedulingInterval() { $method = $reflection->getMethod('get_feed_gen_scheduling_interval'); $method->setAccessible(true); - $feed_gen_interval = $method->invoke($this->feed); - $this->assertEquals(Heartbeat::EVERY_5_MINUTES, $feed_gen_interval, 'The feed gen scheduling interval should be Heartbeat::EVERY_5_MINUTES.'); + $feed_gen_scheduling_interval = $method->invoke($this->feed); + $this->assertEquals(Heartbeat::EVERY_5_MINUTES, $feed_gen_scheduling_interval, 'The feed gen scheduling interval should be Heartbeat::EVERY_5_MINUTES.'); } } From 5a6c8d86d99f1d96a35c08e8b9c926c419f681f8 Mon Sep 17 00:00:00 2001 From: Noah Ostrowski Date: Mon, 24 Mar 2025 13:07:34 -0700 Subject: [PATCH 13/14] Exception -> /Exception --- includes/Feed/AbstractFeed.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/Feed/AbstractFeed.php b/includes/Feed/AbstractFeed.php index 7347ed84c..bf6141960 100644 --- a/includes/Feed/AbstractFeed.php +++ b/includes/Feed/AbstractFeed.php @@ -171,7 +171,7 @@ public function send_request_to_upload_feed(): void { facebook_for_woocommerce()-> get_api()-> create_common_data_feed_upload( $cpi_id, $data ); - } catch ( Exception $exception ) { + } catch ( \Exception $exception ) { \WC_Facebookcommerce_Utils::logExceptionImmediatelyToMeta( $exception, [ From 68d4cee6d1742f903b54aad692e1b32167b11e5a Mon Sep 17 00:00:00 2001 From: Noah Ostrowski Date: Mon, 24 Mar 2025 15:34:16 -0700 Subject: [PATCH 14/14] Checking for CMS ID being set as well in should_skip_feed and updated unit test --- includes/Feed/AbstractFeed.php | 6 ++++-- tests/Unit/Feed/AbstractFeedTest.php | 10 +++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/includes/Feed/AbstractFeed.php b/includes/Feed/AbstractFeed.php index bf6141960..f2f9f92bc 100644 --- a/includes/Feed/AbstractFeed.php +++ b/includes/Feed/AbstractFeed.php @@ -146,9 +146,11 @@ public function regenerate_feed(): void { * @since 3.5.0 */ public function should_skip_feed(): bool { - $cpi_id = facebook_for_woocommerce()->get_connection_handler()->get_commerce_partner_integration_id(); + $connection_handler = facebook_for_woocommerce()->get_connection_handler(); + $cpi_id = $connection_handler->get_commerce_partner_integration_id(); + $cms_id = $connection_handler->get_commerce_merchant_settings_id(); - return empty( $cpi_id ); + return empty( $cpi_id ) || empty( $cms_id ); } /** diff --git a/tests/Unit/Feed/AbstractFeedTest.php b/tests/Unit/Feed/AbstractFeedTest.php index 2eedf854a..2c05385f7 100644 --- a/tests/Unit/Feed/AbstractFeedTest.php +++ b/tests/Unit/Feed/AbstractFeedTest.php @@ -58,9 +58,17 @@ public function setUp(): void { public function testShouldSkipFeed() { update_option( 'wc_facebook_commerce_partner_integration_id', '1841465350002849' ); - $this->assertFalse( $this->feed->should_skip_feed(), 'Feed should not be skipped when CPI ID is not empty.' ); + update_option( 'wc_facebook_commerce_merchant_settings_id', '1352794439398752' ); + $this->assertFalse( $this->feed->should_skip_feed(), 'Feed should not be skipped when CPI ID and CMS ID are set.' ); update_option( 'wc_facebook_commerce_partner_integration_id', '' ); + update_option( 'wc_facebook_commerce_merchant_settings_id', '1352794439398752' ); $this->assertTrue( $this->feed->should_skip_feed(), 'Feed should be skipped when CPI ID is empty.' ); + update_option( 'wc_facebook_commerce_partner_integration_id', '1841465350002849' ); + update_option( 'wc_facebook_commerce_merchant_settings_id', '' ); + $this->assertTrue( $this->feed->should_skip_feed(), 'Feed should be skipped when CMS ID is empty.' ); + update_option( 'wc_facebook_commerce_partner_integration_id', '' ); + update_option( 'wc_facebook_commerce_merchant_settings_id', '' ); + $this->assertTrue( $this->feed->should_skip_feed(), 'Feed should be skipped when both CPI ID and CMS ID are empty.' ); } public function testGetFeedSecret() {