Add get_entry_count() to product feed FeedInterface#64394
Conversation
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>
📝 WalkthroughWalkthroughA new Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
plugins/woocommerce/src/Internal/ProductFeed/Storage/JsonFileFeed.php (1)
100-144:⚠️ Potential issue | 🟡 MinorConsider resetting
$entry_countinstart().If
start()is called twice on the same instance (e.g., to generate a fresh feed),$entry_countpersists from the previous run. The nextadd_entry()will then write a leading,after the opening[, producing invalid JSON — andget_entry_count()will report a count that includes the previous run.Even if reuse isn't currently a supported flow, resetting the counter (and ideally
$file_completed/$file_url) instart()makes the API more robust and the reported count unambiguously scoped to the current run.🛠️ Suggested guard
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.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugins/woocommerce/src/Internal/ProductFeed/Storage/JsonFileFeed.php` around lines 100 - 144, start() currently does not reset state from previous runs which allows $entry_count (and related state) to carry over and produce invalid JSON when add_entry() writes separators; modify the start() method to reset $this->entry_count = 0 and also clear $this->file_completed = false and $this->file_url = '' (or null) at the beginning of start() so that get_entry_count() and subsequent add_entry() behavior are correctly scoped to the new feed generation.
🧹 Nitpick comments (1)
plugins/woocommerce/src/Internal/ProductFeed/Storage/JsonFileFeed.php (1)
152-168:fwrite()failure is counted as a successful entry.
fwrite()can returnfalseor a short write, but$this->entry_countis incremented unconditionally. If a write fails partway through,get_entry_count()will overcount and the separator logic will emit a comma for a row that was never (fully) written, producing malformed JSON.Since the stated purpose of this counter is to report the rows actually written, consider guarding the increment on the write result:
🛠️ Suggested guard
- if ( $this->entry_count > 0 ) { - fwrite( $this->file_handle, ',' ); - } - - fwrite( $this->file_handle, $json ); - ++$this->entry_count; + $payload = ( $this->entry_count > 0 ? ',' : '' ) . $json; + $written = fwrite( $this->file_handle, $payload ); + if ( false === $written || $written < strlen( $payload ) ) { + return; + } + ++$this->entry_count;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugins/woocommerce/src/Internal/ProductFeed/Storage/JsonFileFeed.php` around lines 152 - 168, The add_entry method currently increments $this->entry_count regardless of fwrite outcomes; change add_entry (in class JsonFileFeed) to check the return value(s) from fwrite when writing the separator and the JSON payload, only incrementing $this->entry_count after confirming the full expected byte count was written (handle short writes by looping until total bytes written equals strlen($json) and the comma write succeeded, or treat a failure and abort without increment); ensure the separator (the comma) is only emitted when the previous entry was actually written so get_entry_count and the resulting JSON stay consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@plugins/woocommerce/src/Internal/ProductFeed/Storage/JsonFileFeed.php`:
- Around line 100-144: start() currently does not reset state from previous runs
which allows $entry_count (and related state) to carry over and produce invalid
JSON when add_entry() writes separators; modify the start() method to reset
$this->entry_count = 0 and also clear $this->file_completed = false and
$this->file_url = '' (or null) at the beginning of start() so that
get_entry_count() and subsequent add_entry() behavior are correctly scoped to
the new feed generation.
---
Nitpick comments:
In `@plugins/woocommerce/src/Internal/ProductFeed/Storage/JsonFileFeed.php`:
- Around line 152-168: The add_entry method currently increments
$this->entry_count regardless of fwrite outcomes; change add_entry (in class
JsonFileFeed) to check the return value(s) from fwrite when writing the
separator and the JSON payload, only incrementing $this->entry_count after
confirming the full expected byte count was written (handle short writes by
looping until total bytes written equals strlen($json) and the comma write
succeeded, or treat a failure and abort without increment); ensure the separator
(the comma) is only emitted when the previous entry was actually written so
get_entry_count and the resulting JSON stay consistent.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: 014cd627-3221-4119-9b76-b27e130e7d51
📒 Files selected for processing (4)
plugins/woocommerce/changelog/add-feed-interface-get-entry-countplugins/woocommerce/src/Internal/ProductFeed/Feed/FeedInterface.phpplugins/woocommerce/src/Internal/ProductFeed/Storage/JsonFileFeed.phpplugins/woocommerce/tests/php/src/Internal/ProductFeed/Storage/JsonFileFeedTest.php
Testing GuidelinesHi @daledupreez , Apart from reviewing the code changes, please make sure to review the testing instructions (Guide) and verify that relevant tests (E2E, Unit, Integration, etc.) have been added or updated as needed. Reminder: PR reviewers are required to document testing performed. This includes:
|
Test using WordPress PlaygroundThe changes in this pull request can be previewed and tested using a WordPress Playground instance. Test this pull request with WordPress Playground. Note that this URL is valid for 30 days from when this comment was last updated. You can update it by closing/reopening the PR or pushing a commit that changes plugin code. |
malithsen
left a comment
There was a problem hiding this comment.
Looks good to me on inspection.
daledupreez
left a comment
There was a problem hiding this comment.
The change looks OK to me from inspection, but I have concerns about how we're introducing the change to the interface, as I suspect there are other plugins that have extended this interface, and this could qualify as a breaking change given that they won't implement this method yet.
I think we need to look into any standard WooCommerce practices around evolving interfaces, as I am concerned that this particular approach could be problematic. (As an example, version 10.6.0 of the Stripe plugin would not implement this interface if it was installed on top of this code.)
- 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>
|
Thanks @daledupreez. On the practical side: woocommerce-gateway-stripe#5319 already implements |
|
@coderabbitai Addressed the outside-diff suggestion in e61603d: Skipping the |
|
Tip For best results, initiate chat on the files or code changes.
The state-reset changes look great. Resetting Your reasoning on the ✏️ Learnings added
|
daledupreez
left a comment
There was a problem hiding this comment.
I wasn't sure if other plugins may have started using the interface, so I double-checked whether any public repos reference Automattic\WooCommerce\Internal\ProductFeed\Feed\FeedInterface:
- GitHub results - it looks like it's only WooCommerce and the woocommerce-gateway-stripe (plus forks), as well as an archived WooCommerce repo that was the source for the implementation.
- GitLab results (requires registration/login) - no results
I would also like to do a full-text search of the WordPress.org plugin directory to confirm there are no other usages, but I am not sure if there is an easy way to do that.
I think we should be OK, as we don't have any WooCommerce or Automattic usage, but I wanted to triple-check.
…WooCommerce Stripe Gateway (#65965) Remove get_entry_count() from product feed FeedInterface PR #64394 added get_entry_count() as a required method on FeedInterface, shipping in 10.9.0. Because the interface is implemented by third-party code — notably the WooCommerce Stripe Gateway's WC_Stripe_Agentic_Commerce_Csv_Feed — adding a required method is a backward-incompatible change. Stripe versions that predate their own get_entry_count() implementation (added in Stripe 10.7) fatal on load under 10.9.0: Class WC_Stripe_Agentic_Commerce_Csv_Feed contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (...FeedInterface::get_entry_count) No core code calls get_entry_count() through the interface; the method is only used on the concrete JsonFileFeed (and by consumers on their own feed classes). Remove it from the interface to restore compatibility, keeping the implementation and its tests on JsonFileFeed intact. Refs #64394
…try_count() breaking older WooCommerce Stripe Gateway (#65972) Fix fatal error from FeedInterface::get_entry_count() breaking older WooCommerce Stripe Gateway (#65965) Remove get_entry_count() from product feed FeedInterface PR #64394 added get_entry_count() as a required method on FeedInterface, shipping in 10.9.0. Because the interface is implemented by third-party code — notably the WooCommerce Stripe Gateway's WC_Stripe_Agentic_Commerce_Csv_Feed — adding a required method is a backward-incompatible change. Stripe versions that predate their own get_entry_count() implementation (added in Stripe 10.7) fatal on load under 10.9.0: Class WC_Stripe_Agentic_Commerce_Csv_Feed contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (...FeedInterface::get_entry_count) No core code calls get_entry_count() through the interface; the method is only used on the concrete JsonFileFeed (and by consumers on their own feed classes). Remove it from the interface to restore compatibility, keeping the implementation and its tests on JsonFileFeed intact. Refs #64394 Co-authored-by: Cvetan Cvetanov <cvetan.cvetanov@automattic.com>
Submission Review Guidelines
Changes proposed in this Pull Request
Adds a
get_entry_count(): intmethod toFeedInterfaceand implements it onJsonFileFeed. Consumers of the product feed API — notably anyone usingProductWalker— cannot currently get an accurate count of rows that were actually written to a feed:ProductWalker::walk()returns$progress->processed_items, which counts products iterated, not rows persisted. Any row rejected byFeedValidatorInterface::validate_entry()is silently dropped insideProductWalker::iterate(), so the walker count overcounts whenever validation fails.This change was prompted by reviewer feedback on woocommerce-gateway-stripe#5319 (1, 2), where the Stripe plugin had to add the equivalent method to its own CSV feed class to fix an incorrect "synced product count" on the Agentic Commerce dashboard. Pulling it into the interface keeps every
FeedInterfaceimplementation consistent and removes the need for consumer-sideinstanceofchecks.Summary of changes
FeedInterface: newget_entry_count(): intcontract method.JsonFileFeed: implementsget_entry_count()by tracking a counter inadd_entry().JsonFileFeedTest.How to test the changes in this Pull Request
Automated:
pnpm --filter=@woocommerce/plugin-woocommerce test:php:env -- --filter 'JsonFileFeedTest|ProductWalkerTest'passes (13 tests / 443 assertions).pnpm --filter=@woocommerce/plugin-woocommerce lint:php:changesclean.pnpm --filter=@woocommerce/plugin-woocommerce lint:changes:branchclean.composer exec -- phpstan analyse …/FeedInterface.php …/JsonFileFeed.php --memory-limit=2Gclean.Manual:
JsonFileFeed, callstart(), add N entries, thenend().get_entry_count()returns N.add_entry()made beforestart()(i.e. when the file handle isn't open) do not count.Testing that has already taken place
JsonFileFeedTestandProductWalkerTeststill pass with the refactoredadd_entry()(counter-based instead of booleanhas_entries).Changelog entry
Changelog Entry Details
Significance
Type
Message
Add
get_entry_count()toFeedInterfaceso product feed consumers can report the number of rows actually written to the feed (distinct from the number of products iterated byProductWalker).Comment
Changelog Entry Comment
Comment
🤖 Generated with Claude Code