If you’ve ever run a WooCommerce store, or built one for a client, you know how often this request comes up:
“Can I export all my orders to a CSV file for my accountant?”
Yes, there are plugins that handle this. But sometimes, you want a lightweight, programmatic solution that gives you complete control over which fields are exported.
CSV exports are invaluable for:
- Accountants → monthly order reports.
- Store managers → checking sales performance.
- Marketing teams → analyzing customer data.
- Suppliers → generating purchase or shipping lists.
In this guide, I’ll show you step by step how to export WooCommerce orders into CSV files using nothing more than PHP.
If you’re new to CSV handling, check out my Complete Guide to Working With CSV in WordPress & PHP.
Why Programmatic Export vs Plugins?
Plugins are great, but sometimes they’re too heavy. They add dashboards, advanced settings, and database overhead you don’t always need.
By writing your own export logic, you get:
- Full control → export only the fields you want.
- Lightweight code → no plugin bloat.
- Custom workflows → automate exports or restrict by role.
Basic WooCommerce Order Export
Here’s how to export order IDs, customer emails, and totals:
<?php
add_action('admin_init', function() {
if (isset($_GET['export_orders_csv'])) {
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=orders.csv');
$output = fopen('php://output', 'w');
fputcsv($output, array('Order ID', 'Customer Email', 'Total'));
$args = array(
'limit' => -1,
'orderby' => 'date',
'order' => 'DESC',
);
$orders = wc_get_orders($args);
foreach ($orders as $order) {
fputcsv($output, array(
$order->get_id(),
$order->get_billing_email(),
$order->get_total()
));
}
fclose($output);
exit;
}
});
Visit yoursite.com/wp-admin/?export_orders_csv=1 and download all orders as orders.csv.
Export Orders With Product Details
Often, clients need line-item details:
fputcsv($output, array('Order ID', 'Customer Email', 'Product', 'Quantity', 'Line Total'));
foreach ($orders as $order) {
foreach ($order->get_items() as $item) {
fputcsv($output, array(
$order->get_id(),
$order->get_billing_email(),
$item->get_name(),
$item->get_quantity(),
$item->get_total()
));
}
}
Now each product in an order is listed in the CSV, perfect for inventory and suppliers.
Export Orders by Date Range or Status
You can filter orders by status (completed, refunded, pending) or by date range:
$args = array(
'status' => 'completed',
'date_created' => '>' . (new DateTime('first day of this month'))->format('Y-m-d H:i:s'),
);
$orders = wc_get_orders($args);
Example: Export only completed orders from this month.
Export Customers From Orders
Want a unique customer list with lifetime spend?
fputcsv($output, array('Customer Name', 'Email', 'Total Spent'));
$customers = array();
foreach ($orders as $order) {
$email = $order->get_billing_email();
if (!isset($customers[$email])) {
$customers[$email] = array(
'name' => $order->get_formatted_billing_full_name(),
'email' => $email,
'spent' => $order->get_total()
);
} else {
$customers[$email]['spent'] += $order->get_total();
}
}
// Loop through customers.
foreach ($customers as $customer) {
fputcsv($output, $customer);
}
Great for loyalty programs and email campaigns.
Adding an Export Button in WooCommerce Admin
You can make this client-friendly by adding an export button in WooCommerce admin:
add_action('admin_menu', function() {
add_submenu_page(
'woocommerce',
'Export Orders',
'Export Orders',
'manage_woocommerce',
'wc-export-orders',
function() {
echo '<div class="wrap"><h1>Export WooCommerce Orders</h1>';
echo '<a href="'.admin_url('?export_orders_csv=1').'" class="button button-primary">Download Orders CSV</a>';
echo '</div>';
}
);
});
Now your client has a native WooCommerce menu option.
Best Practices for WooCommerce CSV Exports
Writing CSV export code that “just works” is one thing. Writing CSV export code that is secure, scalable, and client-friendly is another. WooCommerce sites often handle sensitive customer data and large datasets, so here are some best practices to keep in mind.
1. Restrict Access to Trusted Roles
WooCommerce orders contain personal and financial data (emails, addresses, totals). Never let just anyone export them.
if ( ! current_user_can('manage_woocommerce') ) {
wp_die('Unauthorized access');
}
By default, manage_woocommerce is assigned to shop managers and admins, perfect for this use case. If you need more granular control, create a custom capability (e.g., export_orders_csv) and assign it only to specific roles.
2. Use Nonces for Security
If you create export buttons or forms in the admin, always include nonces to prevent CSRF attacks.
wp_nonce_field('wc_export_orders', 'wc_export_nonce');
Then verify before running the export:
if ( ! wp_verify_nonce($_POST['wc_export_nonce'], 'wc_export_orders') ) {
wp_die('Security check failed');
}
Without this, an attacker could trick a logged-in shop manager into exporting sensitive data without realizing it.
3. Escape and Sanitize All Data
Even though CSVs are “just text,” exporting raw database values can expose you to stored XSS vulnerabilities (malicious data saved in the DB could execute when opened in Excel).
Always sanitize and escape:
fputcsv($output, array(
esc_html($order->get_billing_email()),
esc_html($item->get_name()),
absint($item->get_quantity()),
wc_price($item->get_total())
));
This ensures the CSV is safe to open in Excel or Google Sheets.
4. Handle Large Stores with Care
A small shop with 200 orders is easy. A store with 50,000+ orders will crash if you try to export everything at once.
Best practices:
- Use
limitandoffsetto process in batches. - For large exports, offload to WP-CLI to avoid browser timeouts.
- Consider background jobs (using Action Scheduler) for huge reports.
See my guide: Working With Large CSV Files in PHP Without Timeouts.
5. Add Filters for Flexible Reports
Instead of exporting everything, give clients options:
- Filter by order status (completed, refunded, pending).
- Filter by date range (this month, last year).
- Filter by customer group or country.
This makes CSV exports faster, smaller, and much more useful.
6. Log Exports for Transparency
For compliance (GDPR, CCPA, HIPAA in some cases), you may need to log:
- Who exported the file.
- When it was exported.
- What type of data was included.
A simple approach is to save logs in a custom table or in wp_options with user ID + timestamp.
7. Protect Downloaded Files
If you save the CSV file on the server instead of streaming it directly, make sure:
- It’s stored in a non-public directory.
- It’s deleted after a short time (e.g., 24 hours).
- Access is restricted to logged-in admins/shop managers.
Never leave customer data lying around in /wp-content/uploads/.
8. Make Exports User-Friendly
Clients love buttons and feedback:
- Add clear buttons: “Export Orders CSV”, “Export Customers CSV”.
- Show success/failure messages.
- Add progress bars for large exports (AJAX-based).
It makes the feature feel professional and avoids “did it work?” confusion.
9. Think About Data Compliance
CSV exports mean customer data is leaving the site. That data must be handled carefully:
- Encrypt CSVs if sending via email.
- Use HTTPS for all downloads.
- Educate clients about storing CSV files securely.
As a developer, your job doesn’t end with code, it extends to protecting your client’s business reputation.
Conclusion
Exporting WooCommerce orders to CSV programmatically is easier than you might think. With just a few lines of PHP, you can give store owners exactly what they want:
- Quick order reports for accountants.
- Product breakdowns for suppliers.
- Customer lists for marketing.
Want to go deeper? Check out my Complete Guide to Working With CSV in WordPress & PHP for imports, large file handling, and advanced CSV workflows.
Or, if you’d rather let an expert build it for you, explore my WordPress Development Services or contact me directly.






