Skip to content

WP Packages is our new WPackagist replacement that's 17x faster and updates every 5 minutes

  1. Blog

WooCommerce CSV Exports Are Silently Broken with S3 Uploads

Ben Word Ben Word

If you use WooCommerce with S3 Uploads, your analytics exports might be quietly failing and not sending any emails, despite Action Scheduler saying the job was complete.

From Analytics > Revenue, you click the Download button. The network tab shows the POST to /wc-analytics/reports/revenue/export with a payload:

{
  "report_args": {
    "interval": "day",
    "orderby": "date",
    "order": "desc",
    "page": 1,
    "per_page": 25,
    "after": "2025-01-01T00:00:00",
    "before": "2025-12-31T23:59:59"
  },
  "email": true
}

The response includes an export_id and a status link:

{
  "message": "Your report file is being generated.",
  "export_id": "12312312312312",
  "_links": {
    "status": [
      {
        "href": "https://example.com/wp-json/wc-analytics/reports/revenue/export/12312312312312/status"
      }
    ]
  }
}

But then no email is sent.

Checking WooCommerce > Status > Scheduled Actions, the woocommerce_admin_report_export batch jobs show “Complete.” The woocommerce_admin_email_report_download_link action ran and everything looks healthy in the admin.

Since the email never arrived, we dug into the export status endpoint code and found that when percent_complete reaches 100, it constructs a download_url from the export ID and report type. Using the export ID from the Scheduled Actions args, we manually hit:

/wp-admin/?action=woocommerce_admin_download_report_csv&filename=wc-revenue-report-export-12312312312312

A CSV downloaded, but with only headers:

Date,Orders,"Gross sales",Returns,Coupons,"Net sales",Taxes,Shipping,"Total sales"

Why it’s silent

WooCommerce’s batch exporter writes CSV data in WC_CSV_Batch_Exporter::write_csv_data(). The file operations use @fopen and @file_put_contents with silenced errors. When the write fails, no exception is thrown, nothing is logged, and the Action Scheduler job just “completes” with zero data written.

What’s happening

write_csv_data() opens the CSV file with fopen mode a+ (read + append):

$fopen_mode = apply_filters( 'woocommerce_csv_exporter_fopen_mode', 'a+' );
$fp = fopen( $this->get_file_path(), $fopen_mode );

When you’re running S3 Uploads, wp_upload_dir() returns an s3:// path. The S3 stream wrapper only supports r, w, a, and x — the + variants require seekable streams, which S3 objects aren’t. So fopen fails, $fp is false, and the data is never written.

When we tried generating the export via WP-CLI, the errors were no longer silenced:

PHP Warning: Mode not supported: a+. Use one 'r', 'w', 'a', or 'x'.
  in /var/www/public/app/mu-plugins/s3-uploads/inc/class-stream-wrapper.php on line 985

PHP Warning: fopen(s3://bucket/uploads/woocommerce_uploads/reports/wc-revenue-report-export.csv):
  Failed to open stream: "S3_Uploads\Stream_Wrapper::stream_open" call failed
  in /var/www/public/app/plugins/woocommerce/includes/export/abstract-wc-csv-batch-exporter.php on line 151

Fixing the CSV generation

WooCommerce added a hook in 6.8.0 via woocommerce/woocommerce#33652 that defaults to a+.

To fix the CSV generation, you’ll have to add a filter that overrides this to a, which is S3-compatible:

add_filter('woocommerce_csv_exporter_fopen_mode', fn () => 'a');

If you’re routing uploads through any S3 stream wrapper, you’re affected by this. The exports will always produce headers-only files with no data rows and the email is never sent.

Issue submitted to WooCommerce: https://github.com/woocommerce/woocommerce/issues/63835

About the author

Ben Word

Ben Word has been creating WordPress sites since 2004. He loves dogs, climbing, and yoga, and is passionate about helping people build awesome things on the web.

Subscribe for updates

Join over 8,000 subscribers for the latest Roots updates, WordPress plugin recommendations, modern WordPress projects, and web development tips.

One last step! Check your email for a verification link.