A production-ready WordPress plugin for exporting WooCommerce orders to CSV/XLSX with support for product-level custom codes and metadata.
- Flexible Export Formats: CSV (default) and XLSX output
- Custom Column Selection: Choose which order, item, and product fields to include
- Product Custom Codes: Map product meta keys or taxonomy terms to custom columns
- Export Modes: Export as one row per line item or one row per order
- Advanced Filtering: Filter orders by date range and status
- Performance Optimized: Stream output for large datasets (3,000+ orders)
- Export Logging: Track all export operations with filters applied
- Extensible: Hooks and filters for custom development
- Security: Proper nonces, capability checks, and sanitization
- WordPress 6.0+
- WooCommerce 6.0+
- PHP 7.4+
- Download the plugin or clone into your
wp-content/plugins/directory - Navigate to the plugin in WordPress admin and activate
- Go to WooCommerce → Custom Order Export
-
Select Filters
- Choose date range (optional)
- Select order statuses to include
-
Choose Export Format
- CSV or XLSX
- Set CSV delimiter (comma, semicolon, tab, pipe)
- Configure column headers inclusion
-
Select Columns
- Order fields (ID, date, customer info, totals)
- Line item fields (product name, SKU, quantity, price)
- Product fields (categories)
-
Add Custom Code Mappings
- Map product meta keys or taxonomies to export columns
- Supports multiple terms per product
Export a product custom field stored as post meta:
Column Name: product_code
Source Type: Product Meta
Meta Key: _product_code
This exports the value of get_post_meta( $product_id, '_product_code', true )
Export a product taxonomy (like a custom "Collection" taxonomy):
Column Name: product_collection
Source Type: Taxonomy
Taxonomy Name: product_collection
This exports wp_get_post_terms( $product_id, 'product_collection', array('fields' => 'names') )
For WooCommerce attributes (stored as taxonomy pa_*):
Column Name: metal_type
Source Type: Taxonomy
Taxonomy Name: pa_metal
By default, the export includes:
order_id, order_date, customer_name, customer_email, billing_phone,
shipping_address, payment_method, order_total, product_id, sku,
product_name, quantity, line_total, product_code, product_categories
The plugin creates a logging table (wp_wexport_logs) with the following columns:
id: Auto-increment IDexport_date: Timestamp of exportfilters: JSON of filters appliedfile_path: Path to exported filerows_exported: Number of rows in exportexport_format: csv or xlsxuser_id: ID of user who triggered exportstatus: success or errorerror_message: Error details if applicable
// Add or modify order query arguments
apply_filters( 'wexport_order_query_args', $args );
// Modify custom code mappings
apply_filters( 'wexport_custom_code_mappings', $mappings );// Before export starts
do_action( 'wexport_before_export', $manager );
// After export completes
do_action( 'wexport_after_export', $manager, $file_path, $rows_exported );- In your product edit screen or via code, save product meta:
update_post_meta( $product_id, '_product_code', 'PROD-12345' );- In WExport, add a custom code mapping:
- Column Name:
product_code - Source Type:
Product Meta - Meta Key:
_product_code
- Column Name:
- Register a custom product taxonomy:
register_taxonomy(
'product_code',
'product',
array(
'label' => 'Product Code',
'rewrite' => array( 'slug' => 'product-code' ),
)
);- Assign terms to products via admin or code:
wp_set_post_terms( $product_id, array( 'PROD-12345' ), 'product_code' );- In WExport, add a custom code mapping:
- Column Name:
product_code - Source Type:
Taxonomy - Taxonomy Name:
product_code
- Column Name:
woocommerce-custom-order-export/
├── woocommerce-custom-order-export.php # Main plugin file
├── composer.json # Composer dependencies
├── composer.lock # Locked dependency versions
├── phpunit.xml # PHPUnit configuration
├── README.md # This file
├── CHANGELOG.md # Version history
├── LICENSE # GPL v2 license
├── .gitignore # Git ignore rules
│
├── includes/ # Core plugin classes
│ ├── class-export-manager.php # Main export orchestration
│ ├── class-export-formatter.php # CSV/XLSX data formatting
│ ├── class-export-logger.php # Export logging and tracking
│ ├── class-xlsx-exporter.php # XLSX file generation
│ ├── class-ajax-handler.php # AJAX request handling
│ ├── class-template-manager.php # Template CRUD operations
│ ├── class-template-ajax-handler.php # Template AJAX operations
│ └── class-import-manager.php # Template import/export
│
├── admin/ # WordPress admin interface
│ ├── class-admin-page.php # Admin page controller
│ ├── admin-page.php # Admin UI HTML template
│ ├── css/
│ │ ├── admin-styles.css # Main admin styling
│ │ ├── notifications.css # Notification system styling
│ │ └── template-styles.css # Template UI styling
│ └── js/
│ ├── admin-ui.js # Main admin interface logic
│ ├── notifications.js # Notification system
│ └── template-manager.js # Template frontend logic
│
├── tests/ # PHPUnit tests
│ ├── bootstrap.php # Test bootstrap configuration
│ └── test-export-manager.php # Export manager tests
│
└── vendor/ # Composer dependencies
├── phpoffice/phpspreadsheet/ # XLSX generation library
├── phpunit/phpunit/ # PHPUnit testing framework
├── wp-coding-standards/wpcs/ # WordPress coding standards
└── [other dependencies...]
Run PHPUnit tests using Composer:
# Run all tests
composer test
# Run with coverage report
composer test -- --coverage-html coverage/Tests are located in the tests/ directory and configured via phpunit.xml.
-
Verify Product Meta Export
- Create a product with custom meta key
_test_code= "TEST123" - Add custom code mapping in WExport (Meta type)
- Export and verify column contains "TEST123"
- Create a product with custom meta key
-
Verify Taxonomy Export
- Assign a product to a custom taxonomy term
- Add custom code mapping in WExport (Taxonomy type)
- Export and verify column contains term name
-
Large Dataset Test
- With 3,000+ orders, verify export completes without memory errors
- Check that file is created and downloaded correctly
-
Multi-Item Order Test
- Create order with 3 line items
- Export in "line_item" mode: should see 3 rows
- Export in "order" mode: should see 1 row with products joined
-
Special Characters Test
- Create product with quotes, commas, newlines in name
- Verify CSV escaping works correctly in exported file
-
Date Range Filtering Test
- Export with both from and to dates: verify complete range is applied
- Export with only from date: verify all orders after that date
- Export with only to date: verify all orders before that date
-
Template System Test
- Save a template with custom columns
- Load the template and verify all settings are restored
- Set as default and reload page to verify auto-loading
- Duplicate and edit templates
- Orders are fetched in batches (default 100 per batch)
- CSV is streamed to disk via
fputcsv() - No order or item data stored in memory simultaneously
- Processing time depends on server speed and data size
- Recommend increasing PHP timeout for very large exports
- Consider exporting by date ranges for large organizations
Ensure /wp-content/uploads/wexport/ directory exists and is writable:
chmod 755 wp-content/uploads/wexport/-
Verify the meta key exists on products:
get_post_meta( $product_id, '_your_meta_key', true )
-
Verify the taxonomy exists and is assigned to product:
wp_get_post_terms( $product_id, 'your_taxonomy' )
-
Check that custom code mapping is configured in WExport settings
Ensure "Include column headers" and "Use UTF-8 BOM" are both checked for Excel compatibility.
- includes/ - Core plugin classes (Export_Manager, Export_Logger, Exporters, Template_Manager)
- admin/ - WordPress admin interface (class-admin-page.php, templates, styles, JavaScript)
- tests/ - PHPUnit unit and integration tests
- vendor/ - Composer dependencies (PhpSpreadsheet, WordPress Coding Standards)
The project follows WordPress Coding Standards. Run checks with:
# Check code style
composer phpcs
# Auto-fix style issues
composer phpcbf-
Export_Manager (
includes/class-export-manager.php)- Orchestrates the export process
- Queries orders in batches
- Applies filters and custom code mappings
- Delegates formatting to exporter classes
-
CSV_Exporter / XLSX_Exporter (
includes/class-*-exporter.php)- Format-specific export logic
- Stream data to files
- Handle styling and encoding
-
Export_Logger (
includes/class-export-logger.php)- Tracks export operations in database
- Logs filters applied, file paths, status
-
Template_Manager (
includes/class-template-manager.php)- User-scoped template persistence
- CRUD operations for templates
- Default template handling
-
Admin_Page (
admin/class-admin-page.php)- Generates admin UI
- Handles form data validation
- Provides preview functionality
- Update column selection UI in
admin/admin-page.php - Add column to available columns list in
Export_Manager::get_available_columns() - Implement column data retrieval in
Export_Formatter::format_item() - Update default export columns if needed
- Create filter UI in
admin/admin-page.php - Modify
Export_Manager::get_orders_batch()to apply new filter - Update
Export_Loggerto track new filter type - Add validation in
Admin_Page::validate_filters()
- Create new exporter class extending base logic
- Implement file writing in
export()method - Register in
Export_Manager::get_exporter() - Add format option to admin UI
Filters:
// Modify order query arguments
apply_filters( 'wexport_order_query_args', $args );
// Modify custom code mappings
apply_filters( 'wexport_custom_code_mappings', $mappings );
// Modify export columns
apply_filters( 'wexport_export_columns', $columns );Actions:
// Before export starts
do_action( 'wexport_before_export', $manager );
// After export completes
do_action( 'wexport_after_export', $manager, $file_path, $rows_exported );Enable debug logging by adding to wp-config.php:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );Check logs in wp-content/debug.log. The plugin uses error_log() for server-side debugging.
For frontend debugging, check browser console (F12) for detailed logging during export operations.
# Install dependencies
composer install
# Run tests
composer test
# Run with verbose output
composer test -- --verboseTest files use WordPress test utilities if bootstrapped properly. See tests/bootstrap.php for configuration.
Extend export columns via filter:
add_filter( 'wexport_order_query_args', function( $args ) {
$args['meta_query'] = array(
array(
'key' => '_custom_order_field',
'value' => 'value',
)
);
return $args;
});Use WP-Cron:
wp_schedule_event( time(), 'daily', 'wexport_scheduled_export' );
add_action( 'wexport_scheduled_export', function() {
$manager = new WExport\Export_Manager( array(
'format' => 'csv',
'columns' => get_option( 'wexport_default_columns' ),
'order_status' => array( 'wc-completed' ),
));
$file = $manager->export();
// Email result
wp_mail(
get_option( 'admin_email' ),
'Daily Order Export',
'Export completed: ' . $file
);
});Typical performance on standard hosting:
- 100 orders: < 1 second
- 1,000 orders: 5-10 seconds
- 10,000 orders: 1-2 minutes
- 100,000 orders: 15-30 minutes
- All admin actions require
manage_woocommercecapability - Nonces on all forms
- User ID and timestamp logged for all exports
- Meta keys and taxonomy names sanitized before database queries
- CSV output escaped for safe Excel import
For issues or feature requests, please contact support or submit via the plugin support channel.
GPL v2 or later - See LICENSE file
Fixed
- Template System:
remove_variation_from_product_namecheckbox value is now correctly saved in template config and loaded when templates are restored. Previously, this setting was only saved globally but not included in individual template configurations.
Fixed
- Critical: Taxonomy custom columns now correctly show only the variation-specific attribute value for variation products, instead of showing all taxonomy terms from the parent product. When exporting a variation with a selected attribute (e.g., "50g" for
pa_gramaj), only that specific value is now exported, not all available values. - Product variation taxonomy extraction now prioritizes
get_attribute()to retrieve the variation-specific value before falling back towp_get_post_terms(). - Preview and export now have consistent behavior for variation taxonomy values.
- Persist
remove_variation_from_product_nameadmin setting: Store the checkbox state persistently usingupdate_optionfrom both AJAX and non-AJAX flows (preview and export), so the checkbox is remembered for subsequent sessions.
Changed
- Taxonomy handling: Reordered variation attribute extraction logic to check
product->get_attribute()FIRST for variations, ensuring only the selected attribute value is returned, then falling back to taxonomy term queries only if needed. - Simplified taxonomy extraction logic by removing redundant attribute fallback from the else block.
Added
- Checkbox in admin UI to remove variation details from product names on export and preview. The exporter now uses parent product name for variations if this option is enabled.
Changed
- Taxonomy-based custom code mappings now prefer terms assigned to the variation (if the exported item is a variation) and fall back to the parent product if none are present. This makes per-variation attributes (e.g.,
pa_gramaj) export the correct variation value (like "50g").
Fixed
- Date Range Filtering: Fixed critical bug where date range filters were not working correctly
- Previously, when both
date_fromanddate_towere specified, the second filter would overwrite the first - Now uses proper WooCommerce query approach with post-filtering for combined date ranges
- Single date filters (from OR to) use native WooCommerce date_created parameter
- Combined date range filters use PHP-level post-filtering to avoid WooCommerce HPOS incompatibility
- Orders are now correctly filtered by the complete date range
- Previously, when both
- Export now respects both start and end dates when filtering orders
- Fixed TypeError from incompatible date query format with WooCommerce HPOS
Changed
- Improved
get_orders_batch()method with hybrid approach: native query for single conditions, post-filtering for ranges - Date filtering now uses time boundaries (00:00:00 for start, 23:59:59 for end) for accurate daily filtering
- Added custom parameter handling (_wexport_date_from, _wexport_date_to) for post-filtering logic
Changed
- UX Improvement: Replaced browser alerts with user-friendly flyout notifications
- Alerts in template loading logic now display as non-intrusive notification popups
- Notifications support multiple types: success, error, warning, and info
- Auto-dismiss notifications after 3-5 seconds with manual close option
- Improved visual feedback with color-coded notification types
Added
- New notification system with dedicated CSS styling (
admin/css/notifications.css) - Notification JavaScript utility (
admin/js/notifications.js) withWExportNotificationsAPI - Smooth animations for notification appearance and dismissal
- Responsive design for mobile and tablet devices
- Notification types: success (green), error (red), warning (orange), info (blue)
- Template Management Improvements:
- Display currently loaded template in Template section with visual indicator
- "Edit" button for templates to rename and update their configurations
- Visual highlighting of currently loaded template in manage modal
- Track currently loaded template state across sessions
Fixed
- Simplified: Removed unnecessary
plugin_versionandoperation_typecolumns from logging table - Cleaned up database schema to only store essential export information
- Removed complex migration logic that was causing database issues
Changed
- Export logger now only tracks: filters, file_path, rows_exported, export_format, user_id, status, error_message
- Removed
log_export()parameters:operation_type,plugin_version - Removed
migrate_table()method and all related migration logic - Simplified table schema to reduce complexity
Fixed
- Critical: Database migration now properly adds missing
plugin_versionandoperation_typecolumns on export - Simplified migration logic to use direct ALTER TABLE statements instead of dbDelta
- Migration now runs automatically before every export to ensure columns exist
- Added error logging for migration failures
Changed
- Migration function now checks column existence with
INFORMATION_SCHEMAbefore attempting to add - Export AJAX handler now calls
migrate_table()before processing exports - Transient-based migration caching on page load to avoid performance issues
Added
- Auto-load default template - When a user sets a template as default, it now automatically loads on page visit
- Default template ID is passed to frontend and loaded on admin page initialization
Changed
- Template initialization now checks for and loads the default template if one is set
- Updated frontend data localization to include
defaultTemplateId loadDefaultTemplateIfSet()method added to template manager for automatic loading
Fixed
- Critical: Database table migration not running on existing installations
- Added automatic database migration on every plugin load to ensure missing columns are created
- Fixed
plugin_versionandoperation_typecolumns missing on tables created with older versions
Changed
- Plugin now runs
migrate_table()onplugins_loadedhook in addition to activation - Ensures backward compatibility with all existing installations without manual SQL intervention
Fixed
- Critical: Custom code mappings source field was always empty when saving templates
- Fixed form data collection to properly read from the correct input element (text vs select)
- For taxonomy types, now correctly reads from
.custom-code-source-selectinstead of generic.custom-code-source - For meta types, correctly reads from
.custom-code-source-text
Fixed
- Fixed custom code mappings not being properly serialized when saving templates
- Improved template save AJAX request to use FormData API for proper nested array handling
- Added comprehensive debug logging to track data flow during template save operations
Changed
- Template save now uses FormData API instead of plain object spread
- Enhanced error reporting in browser console and server logs
- Added detailed logging for custom codes array processing
Fixed
- Critical: Template system now correctly loads custom column mappings when loading saved templates
- Custom code mappings were not being restored when loading templates due to form data mismatch
- Form now properly clears existing custom code rows before loading template rows
- Added null/undefined checks for safely handling template data
Added
- Template Management System - Save, load, duplicate, and manage export templates
- New
Template_Managerclass for handling template CRUD operations - New
Template_Ajax_Handlerclass for AJAX template operations - Template dropdown selector for quick template loading
- "Manage Templates" modal with table view of all saved templates
- Set default template functionality for automatic loading on page load
- Template duplication and deletion capabilities
- Template import/export as JSON for backup and sharing
Changed
- Updated admin page to include template management interface
- Added template JavaScript handler for frontend operations
- Plugin version bumped from 1.3.8 to 1.4.0
Fixed
- Critical: XLSX export styling methods now compatible with PhpSpreadsheet 1.29+
- Fixed
getFont()method - now usesgetStyle()->getFont() - Fixed
getFill()method - now usesgetStyle()->getFill() - Fixed
getDataType()method - now usesgetStyle()->getNumberFormat() - XLSX header styling (bold, gray background) now works correctly
- Number formatting for decimal values in XLSX files now works
Fixed
- Important: Product variations now correctly export parent product taxonomy terms
- Variation products now inherit category and taxonomy assignments from their parent product
- Product categories now properly resolve for all product variation types
Added
- Automatic parent product detection for variation products
- Proper handling of WooCommerce product variation inheritance in taxonomy extraction
Fixed
- Critical: Taxonomy form data not being properly captured during AJAX form submission
- Fixed FormData construction to correctly extract values from taxonomy select dropdowns
- Improved input visibility toggle to use CSS display properties instead of jQuery show/hide
- Taxonomy terms now properly export when selected from the custom code mapping dropdown
Fixed
- Critical: Custom taxonomy term mappings showing no values in export
- Improved form validation to properly capture taxonomy select values
- Fixed visibility toggle detection in form data collection
- Added taxonomy validation to prevent silent failures on invalid taxonomy names
Fixed
- Critical: Product taxonomy term data not being exported to CSV despite appearing in preview
- Custom taxonomy term extraction now retrieves full term objects instead of only term names
- Both export and preview now access complete term data with proper separators
Fixed
- Critical: Custom code mappings not being included in export/preview
- Form data submission now uses FormData API instead of jQuery serialize()
- Properly handles nested array structure for custom codes (
custom_codes[index][field]) - Custom code columns and product data now correctly appear in exports
Added
- Debug logging for custom code mapping issues
- Browser console logging to show custom codes before AJAX submission
- Server-side error logging for custom code processing (wp-content/debug.log)
Fixed
- Bug: Validation error when using taxonomy dropdown selector
- Form validation now checks only the visible input field (text for meta, dropdown for taxonomy)
- Fixed "Please fill in both Column Name and Source" error during preview/export
Added
- New Feature: Dynamic taxonomy dropdown selector for custom product code mappings
get_available_product_taxonomies()method to fetch all public product taxonomies- Smart input type switching in custom codes UI - text input for meta, select dropdown for taxonomies
- Taxonomy labels displayed with technical names for better user clarity (e.g., "Color (pa_color)")
Fixed
- Bug: Product custom metas not included in preview generation
- Custom code mappings now correctly show in preview data
- Preview now matches final export output
Features
- CSV and XLSX export support
- Product custom codes mapping (meta and taxonomy)
- Order filtering by date range and status
- Export logging and recent exports display
- Flexible column selection
- Template system foundation
Initial Release
- Basic CSV and XLSX export functionality
- WooCommerce order export with customizable columns
- Support for product metadata and custom fields
- Date range and order status filtering
- Export logging to track operations
- Full WordPress and WooCommerce integration
- Security features: nonce verification, capability checks, input sanitization