Commit f7b43d31c9d for woocommerce
commit f7b43d31c9d71681eeb0481d27abbd154866d60a
Author: Wesley Rosa <wesleyjrosa@gmail.com>
Date: Wed May 13 10:15:48 2026 -0300
Add get_entry_count() to product feed FeedInterface (#64394)
* Add get_entry_count() to FeedInterface
Expose the number of rows actually written to the feed so consumers can
report an accurate count. ProductWalker reports the number of products
iterated, which overcounts when FeedValidatorInterface::validate_entry()
silently drops entries before they reach FeedInterface::add_entry().
Implemented on JsonFileFeed by tracking the count in add_entry().
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Reset JsonFileFeed state on start() and correct @since version
- Reset $entry_count, $file_completed, and $file_url at the top of start()
so a feed instance can be regenerated without producing invalid JSON
(carried-over entry_count would emit a leading "," after "[") or
leaking stale completion state into get_entry_count() / get_file_url().
- Add a regression test (test_start_resets_state_from_previous_run)
covering the start -> end -> start -> end flow.
- Bump @since 10.8.0 -> 10.9.0 on FeedInterface::get_entry_count() to
match the current dev version (10.9.0-dev), per review feedback.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
diff --git a/plugins/woocommerce/changelog/add-feed-interface-get-entry-count b/plugins/woocommerce/changelog/add-feed-interface-get-entry-count
new file mode 100644
index 00000000000..4fe3c309c44
--- /dev/null
+++ b/plugins/woocommerce/changelog/add-feed-interface-get-entry-count
@@ -0,0 +1,4 @@
+Significance: minor
+Type: add
+
+Add `get_entry_count()` to `FeedInterface` so product feed consumers can report the number of rows actually written to the feed (distinct from the number of products iterated by `ProductWalker`).
diff --git a/plugins/woocommerce/src/Internal/ProductFeed/Feed/FeedInterface.php b/plugins/woocommerce/src/Internal/ProductFeed/Feed/FeedInterface.php
index a363268f650..2420874df6f 100644
--- a/plugins/woocommerce/src/Internal/ProductFeed/Feed/FeedInterface.php
+++ b/plugins/woocommerce/src/Internal/ProductFeed/Feed/FeedInterface.php
@@ -51,4 +51,16 @@ interface FeedInterface {
* @return string|null The URL of the feed file, null if not ready.
*/
public function get_file_url(): ?string;
+
+ /**
+ * Get the number of entries that have been added to the feed.
+ *
+ * This reflects the rows actually written to the feed, which may be fewer
+ * than the number of products iterated by `ProductWalker` because the
+ * validator can silently drop entries before they reach `add_entry()`.
+ *
+ * @since 10.9.0
+ * @return int Number of entries added to the feed.
+ */
+ public function get_entry_count(): int;
}
diff --git a/plugins/woocommerce/src/Internal/ProductFeed/Storage/JsonFileFeed.php b/plugins/woocommerce/src/Internal/ProductFeed/Storage/JsonFileFeed.php
index 0b418d09b2f..83a63ef680b 100644
--- a/plugins/woocommerce/src/Internal/ProductFeed/Storage/JsonFileFeed.php
+++ b/plugins/woocommerce/src/Internal/ProductFeed/Storage/JsonFileFeed.php
@@ -27,11 +27,11 @@ class JsonFileFeed implements FeedInterface {
public const UPLOAD_DIR = 'product-feeds';
/**
- * Indicates if there are previous entries in the feed.
+ * The number of entries added to the feed.
*
- * @var bool
+ * @var int
*/
- private $has_entries = false;
+ private $entry_count = 0;
/**
* The base name of the feed file.
@@ -98,6 +98,10 @@ class JsonFileFeed implements FeedInterface {
* @throws Exception If the feed directory cannot be created.
*/
public function start(): void {
+ $this->entry_count = 0;
+ $this->file_completed = false;
+ $this->file_url = null;
+
/**
* Allows the current time to be overridden before a feed is stored.
*
@@ -154,16 +158,17 @@ class JsonFileFeed implements FeedInterface {
return;
}
- if ( ! $this->has_entries ) {
- $this->has_entries = true;
- } else {
- fwrite( $this->file_handle, ',' );
+ $json = wp_json_encode( $entry );
+ if ( false === $json ) {
+ return;
}
- $json = wp_json_encode( $entry );
- if ( false !== $json ) {
- fwrite( $this->file_handle, $json );
+ if ( $this->entry_count > 0 ) {
+ fwrite( $this->file_handle, ',' );
}
+
+ fwrite( $this->file_handle, $json );
+ ++$this->entry_count;
}
/**
@@ -184,6 +189,13 @@ class JsonFileFeed implements FeedInterface {
$this->file_completed = true;
}
+ /**
+ * {@inheritDoc}
+ */
+ public function get_entry_count(): int {
+ return $this->entry_count;
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/plugins/woocommerce/tests/php/src/Internal/ProductFeed/Storage/JsonFileFeedTest.php b/plugins/woocommerce/tests/php/src/Internal/ProductFeed/Storage/JsonFileFeedTest.php
index 21947be02c0..2f13234fd7d 100644
--- a/plugins/woocommerce/tests/php/src/Internal/ProductFeed/Storage/JsonFileFeedTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/ProductFeed/Storage/JsonFileFeedTest.php
@@ -83,6 +83,58 @@ class JsonFileFeedTest extends \WC_Unit_Test_Case {
);
}
+ /**
+ * Test that get_entry_count reflects the number of rows written to the feed.
+ */
+ public function test_get_entry_count_reflects_added_entries() {
+ $feed = new JsonFileFeed( 'test-feed' );
+ $this->assertSame( 0, $feed->get_entry_count() );
+
+ $feed->start();
+ $this->assertSame( 0, $feed->get_entry_count() );
+
+ $feed->add_entry( array( 'name' => 'First' ) );
+ $feed->add_entry( array( 'name' => 'Second' ) );
+ $this->assertSame( 2, $feed->get_entry_count() );
+
+ $feed->end();
+ $this->assertSame( 2, $feed->get_entry_count() );
+ }
+
+ /**
+ * Test that add_entry does not count entries added before start().
+ */
+ public function test_get_entry_count_ignores_entries_added_before_start() {
+ $feed = new JsonFileFeed( 'test-feed' );
+ $feed->add_entry( array( 'name' => 'dropped' ) );
+ $this->assertSame( 0, $feed->get_entry_count() );
+ }
+
+ /**
+ * Test that start() resets state from a previous run so the feed can be regenerated.
+ */
+ public function test_start_resets_state_from_previous_run() {
+ $feed = new JsonFileFeed( 'test-feed' );
+ $feed->start();
+ $feed->add_entry( array( 'name' => 'First' ) );
+ $feed->add_entry( array( 'name' => 'Second' ) );
+ $feed->end();
+ $this->assertSame( 2, $feed->get_entry_count() );
+
+ $feed->start();
+ $this->assertSame( 0, $feed->get_entry_count() );
+ $this->assertNull( $feed->get_file_path() );
+
+ $feed->add_entry( array( 'name' => 'Only' ) );
+ $feed->end();
+
+ $this->assertSame( 1, $feed->get_entry_count() );
+ $this->assertSame(
+ wp_json_encode( array( array( 'name' => 'Only' ) ) ),
+ file_get_contents( $feed->get_file_path() )
+ );
+ }
+
/**
* Test that get_file_url returns null if feed is not completed.
*/