Skip to content

Conversation

@imehedi357
Copy link

@imehedi357 imehedi357 commented Jan 2, 2026

Fix withdraw export ignoring filters, and disable the export button while processing using the new exporter.

All Submissions:

  • My code follow the WordPress' coding standards
  • My code satisfies feature requirements
  • My code is tested
  • My code passes the PHPCS tests
  • My code has proper inline documentation
  • I've included related pull request(s) (optional)
  • I've included developer documentation (optional)
  • I've added proper labels to this pull request

Changes proposed in this Pull Request:

  • Fix Status Filter: Switched the controller from v2 to v1 which uses WooCommerce's export functionality.
  • Fix Status Filter: Updated WithdrawExportController to convert the status string (e.g., 'approved') received from the API into its corresponding integer status code (e.g., 1) before querying the database. Previously, passing the string directly caused the query to fail or default to the wrong status.
  • Fix Date Filter: Updated WithdrawExportController to map standard REST API date parameters (after, before) to the internal query arguments (start_date, end_date) required by dokan()->withdraw->all().
  • Frontend Update: Updated the withdraw dashboard frontend (index.tsx) to pass after and before parameters for date filtering instead of start_date and end_date, adhering to the API expectations.
  • UX Improvement: Disabled the "Export" button while an export is in progress to prevent multiple clicks.

Note on Filename: The issue description mentioned that the exported filename should reflect the applied filters (e.g., statement_vendorA_...). This change was not included in this PR. The export functionality relies on Automattic\WooCommerce\Admin\API\Reports\GenericController for generating the file, and modifying the filename generation logic would require overriding significant portions of the core WooCommerce Admin export handling, which was deemed too intrusive and risky for this fix.

Related Pull Request(s)

Closes

How to test the changes in this Pull Request:

  • Steps in the issue link

Changelog entry

fix filtered export and swap to new controller

  • Now, the exported CSV only contains data matching the active filters.
  • Pagination is removed during export to ensure all matching records are included in the generated file.
  • The export process now runs in the background.
  • A loader/spinner has been added to the Export button to provide visual feedback to the user while the export is in progress.

Before Changes

The export function ignored the active status and date filters, downloading an internal default set or all records regardless of what was shown in the table.

Feature Video (optional)

Link of detailed video if this PR is for a feature.

PR Self Review Checklist:

  • Code is not following code style guidelines
  • Bad naming: make sure you would understand your code if you read it a few months from now.
  • KISS: Keep it simple, Sweetie (not stupid!).
  • DRY: Don't Repeat Yourself.
  • Code that is not readable: too many nested 'if's are a bad sign.
  • Performance issues
  • Complicated constructions that need refactoring or comments: code should almost always be self-explanatory.
  • Grammar errors.

FOR PR REVIEWER ONLY:

As a reviewer, your feedback should be focused on the idea, not the person. Seek to understand, be respectful, and focus on constructive dialog.

As a contributor, your responsibility is to learn from suggestions and iterate your pull request should it be needed based on feedback. Seek to collaborate and produce the best possible contribution to the greater whole.

  • Correct — Does the change do what it’s supposed to? ie: code 100% fulfilling the requirements?
  • Secure — Would a nefarious party find some way to exploit this change? ie: everything is sanitized/escaped appropriately for any SQL or XSS injection possibilities?
  • Readable — Will your future self be able to understand this change months down the road?
  • Elegant — Does the change fit aesthetically within the overall style and architecture?

Summary by CodeRabbit

  • New Features

    • Export withdrawal reports with real-time loading feedback during processing.
  • Improvements

    • Enhanced accuracy of withdrawal filters, including status and date range parameters used in export operations.

✏️ Tip: You can customize this high-level summary in your review settings.

@imehedi357 imehedi357 added Needs: Testing This requires further testing Needs: Dev Review It requires a developer review and approval labels Jan 2, 2026
@imehedi357 imehedi357 self-assigned this Jan 2, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 2, 2026

📝 Walkthrough

Walkthrough

The changes fix the export-ignores-filters bug by mapping filter parameters to their backend equivalents (status codes, date ranges) and implementing a client-side export flow with status polling and loading indicators during the export process.

Changes

Cohort / File(s) Summary
Backend Export Parameter Mapping
includes/REST/WithdrawExportController.php
Replaced direct filter values with transformed equivalents: status now converts to code using dokan()->withdraw->get_status_code(...), and after/before parameters map to start_date/end_date for backend consistency.
Frontend Export UI & Polling
src/admin/dashboard/pages/withdraw/index.tsx
Added Loader2 icon import and isExporting state to manage export button appearance. Export button now initiates POST to /dokan/v1/reports/withdraws/export with current filter state, polls export status via pollExportStatus, displays spinner during export, and includes error handling with alert dismissal and state reset.

Sequence Diagram

sequenceDiagram
    actor User
    participant UI as Withdraw Page UI
    participant Controller as WithdrawExportController
    participant ExportSvc as Export Service
    
    User->>UI: Click Export with filters applied
    activate UI
    UI->>UI: Set isExporting = true, show Loader2
    
    rect rgb(200, 220, 255)
    Note over UI,Controller: Export Initiation with Filtered Params
    UI->>Controller: POST /reports/withdraws/export<br/>(report_args: status, start_date, end_date, ...)
    end
    
    activate Controller
    Controller->>Controller: Map status to code<br/>(via get_status_code)
    Controller->>Controller: Map after → start_date<br/>Map before → end_date
    Controller->>ExportSvc: Trigger export with mapped params
    deactivate Controller
    Controller-->>UI: Return export_id
    deactivate UI
    
    rect rgb(220, 255, 220)
    Note over UI,ExportSvc: Status Polling Loop
    loop Until export ready
        UI->>ExportSvc: pollExportStatus(export_id)
        ExportSvc-->>UI: Status (pending/ready/error)
    end
    end
    
    alt Export Ready
        UI->>UI: Set isExporting = false
        UI->>User: Export file available
    else Export Error
        UI->>UI: Set isExporting = false<br/>Show alert
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

Upcoming Release

Suggested reviewers

  • mrabbani
  • shohag121
  • kzamanbd

Poem

🐰 Hops with joy at filtered exports bright,
No more forgotten filters—data now feels right!
With status codes mapped and dates aligned,
The rabbit rejoices: what you see is what you'll find!

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title references switching to WooCommerce exporter and adding proper filtering, which aligns with the core changes in the PR (controller switch and filter parameter mapping).
Description check ✅ Passed The description covers all critical aspects: changes proposed, test steps, before/after scenario, and changelog entry. Most required checklist items are marked complete.
Linked Issues check ✅ Passed The PR addresses the core issue (#5251) by implementing proper status/date filtering and exporting all matching rows across pagination. However, it explicitly excludes filename filtering and export metadata, which were secondary objectives.
Out of Scope Changes check ✅ Passed All changes directly support the primary objective of fixing filtered exports: controller migration, status conversion, date parameter mapping, and UI button state management. No unrelated changes detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/admin/dashboard/pages/withdraw/index.tsx (1)

578-582: Consider using a toast notification instead of alert().

While the error handling logic is correct and the finally block properly resets the state, using alert() for error messages provides a suboptimal user experience. Consider replacing it with a toast or notification component for more modern and user-friendly error feedback.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 30577f8 and 95af0b2.

📒 Files selected for processing (2)
  • includes/REST/WithdrawExportController.php
  • src/admin/dashboard/pages/withdraw/index.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
includes/REST/WithdrawExportController.php (2)
dokan.php (1)
  • dokan (90-92)
includes/Withdraw/Manager.php (1)
  • get_status_code (285-299)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: e2e tests (2, 3)
  • GitHub Check: e2e tests (3, 3)
  • GitHub Check: api tests (1, 1)
  • GitHub Check: e2e tests (1, 3)
🔇 Additional comments (6)
includes/REST/WithdrawExportController.php (2)

98-100: LGTM!

The mapping of after to start_date correctly transforms the REST API parameter to the internal query argument format expected by dokan()->withdraw->all().


102-104: LGTM!

The mapping of before to end_date correctly transforms the REST API parameter to the internal query argument format expected by dokan()->withdraw->all().

src/admin/dashboard/pages/withdraw/index.tsx (4)

24-24: LGTM!

The Loader2 import is correctly added and used for the export loading indicator.


91-91: LGTM!

The isExporting state correctly tracks the export operation status and controls the button's disabled state and loading indicator.


585-595: LGTM!

The conditional rendering provides clear visual feedback during the export process. The loading spinner with "Exporting..." text and the disabled button state create a good user experience.


554-571: Clarify whether per_page: 100 limits the export to 100 records or serves as a batch size for internal pagination.

The export implementation uses WooCommerce's GenericController + ExportableInterface pattern with background job processing (indicated by the polling mechanism). However, the WithdrawExportController::get_items() method directly applies per_page as a database LIMIT without visible pagination looping.

To confirm this fulfills the PR requirement ("export should include all matching rows across pagination"), verify:

  1. Whether WooCommerce's GenericController internally loops through pages during export processing
  2. Or if per_page: 100 acts as a hard limit on total exported records

If the latter, the export should either remove the per_page limit or loop through all pages to fetch complete datasets.

Comment on lines 90 to 92
if ( ! empty( $request['status'] ) ) {
$args['status'] = $request['status'];
$args['status'] = dokan()->withdraw->get_status_code( $request['status'] );
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Consider validating the status conversion result.

If an invalid status somehow bypasses the enum validation or if get_status_code returns null, assigning null to $args['status'] might produce unexpected query behavior. Consider only setting the status if the conversion succeeds:

🔎 Suggested defensive check
 if ( ! empty( $request['status'] ) ) {
-    $args['status'] = dokan()->withdraw->get_status_code( $request['status'] );
+    $status_code = dokan()->withdraw->get_status_code( $request['status'] );
+    if ( null !== $status_code ) {
+        $args['status'] = $status_code;
+    }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if ( ! empty( $request['status'] ) ) {
$args['status'] = $request['status'];
$args['status'] = dokan()->withdraw->get_status_code( $request['status'] );
}
if ( ! empty( $request['status'] ) ) {
$status_code = dokan()->withdraw->get_status_code( $request['status'] );
if ( null !== $status_code ) {
$args['status'] = $status_code;
}
}
🤖 Prompt for AI Agents
In includes/REST/WithdrawExportController.php around lines 90 to 92, the code
assigns $args['status'] directly from
dokan()->withdraw->get_status_code($request['status']) which may return null;
update this to capture the conversion result in a variable, check that it is not
null (or not false) before setting $args['status'], and if the conversion fails
either skip setting the status filter or handle the invalid value (e.g., return
a validation error or use a safe default) to avoid passing null into the query.

@imehedi357
Copy link
Author

@mrabbani, @imtiaz-pranto vai, the feature of the dynamic name of the filtered data is not added. The file name is currently the default name provided from WooCommerce.

@imehedi357 imehedi357 requested a review from mrabbani January 2, 2026 10:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs: Dev Review It requires a developer review and approval Needs: Testing This requires further testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants