How to Fix WooCommerce Analytics Reports for Multi-Currency Stores
If you’re running a multi-currency WooCommerce store with WOOCS and your WooCommerce Analytics reports show incorrect totals, this guide will help you fix it.
The Problem
Symptom: WooCommerce Analytics shows wrong sales figures when you have orders in multiple currencies.
Example:
- Order #1: $100 USD
- Order #2: €100 EUR
- Order #3: £100 GBP
What WooCommerce Analytics shows:
Total Sales: $300
This is WRONG! WooCommerce is adding different currencies without converting them: 100 USD + 100 EUR + 100 GBP ≠ 300 USD
Correct calculation should be:
$100 USD + €100 EUR ($109) + £100 GBP ($127) = $336 USD
Why This Happens
WooCommerce Analytics doesn’t natively support multi-currency. It simply sums all order totals without checking the currency, treating all numbers as if they’re in your base currency.
Affected reports:
- Revenue reports
- Sales by date
- Product sales analytics
- Tax reports
- Shipping reports
This affects:
- Business decisions based on wrong data
- Tax calculations
- Financial reporting
- ROI analysis
The Solution
This code converts all orders to your base currency when displaying WooCommerce Analytics reports, giving you accurate totals.
Step 1: Add Code to Your Site
Add this code to your child theme’s functions.php or use Code Snippets plugin.
Complete code:
/**
* Fix WooCommerce Analytics for multi-currency stores (WOOCS)
* Converts all orders to base currency for accurate reporting
*/
// Clear WooCommerce reports cache (run once, then remove this)
add_action('init', function () {
if (current_user_can('manage_woocommerce')) {
global $wpdb;
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '%_wc_report_%'");
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '%wc_admin_report_%'");
}
});
// Disable Analytics cache to force real-time conversion
add_filter('woocommerce_analytics_enable_cache', '__return_false');
// Convert order totals to base currency in Analytics queries
add_filter('woocommerce_analytics_orders_select_query', function ($results, $args) {
if (!$results || !isset($results->data) || empty($results->data)) {
return $results;
}
$base_currency = get_woocommerce_currency();
foreach ($results->data as $key => $order_data) {
$order_id = $order_data['order_id'];
$order_currency = get_post_meta($order_id, '_order_currency', true);
// Only convert if order currency differs from base currency
if ($order_currency && $order_currency !== $base_currency) {
// Get exchange rate from order meta (rate at time of purchase)
$exchange_rate = get_post_meta($order_id, '_woocs_order_rate', true);
// Fallback to current rate if historical rate not found
if (!$exchange_rate) {
$exchange_rate = woocs_get_exchange_rate($order_currency, $base_currency);
}
// Convert all monetary values
if (isset($order_data['net_total'])) {
$results->data[$key]['net_total'] = floatval($order_data['net_total']) * floatval($exchange_rate);
}
if (isset($order_data['total_sales'])) {
$results->data[$key]['total_sales'] = floatval($order_data['total_sales']) * floatval($exchange_rate);
}
if (isset($order_data['tax_total'])) {
$results->data[$key]['tax_total'] = floatval($order_data['tax_total']) * floatval($exchange_rate);
}
if (isset($order_data['shipping_total'])) {
$results->data[$key]['shipping_total'] = floatval($order_data['shipping_total']) * floatval($exchange_rate);
}
}
}
return $results;
}, 10, 2);
/**
* Helper function to get exchange rate between currencies
*/
function woocs_get_exchange_rate($from_currency, $to_currency) {
global $WOOCS;
if (!isset($WOOCS) || !$WOOCS) {
return 1;
}
$currencies = $WOOCS->get_currencies();
if (isset($currencies[$from_currency]) && isset($currencies[$to_currency])) {
$from_rate = floatval($currencies[$from_currency]['rate']);
$to_rate = floatval($currencies[$to_currency]['rate']);
if ($from_rate > 0) {
return $to_rate / $from_rate;
}
}
return 1;
}
Step 2: Verify Results
- Go to WooCommerce → Analytics → Revenue
- Check your sales totals
- Compare with previous (incorrect) data
- Totals should now be accurate, converted to base currency
How It Works
Part 1: Cache Clearing
add_action('init', function () {
global $wpdb;
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '%_wc_report_%'");
...
});
What it does: Clears old cached reports that contain incorrect data
This code runs only for admin users
Part 2: Disable Analytics Cache
add_filter('woocommerce_analytics_enable_cache', '__return_false');
What it does: Forces WooCommerce Analytics to recalculate data on each view instead of using cached values
Trade-off: Reports may load slightly slower, but data will always be accurate
Part 3: Convert Order Totals
add_filter('woocommerce_analytics_orders_select_query', function ($results, $args) {
// Convert each order to base currency
...
});
What it does:
- Intercepts Analytics database queries
- Checks each order’s currency
- If different from base currency, converts using exchange rate
- Returns converted values to Analytics
Part 4: Exchange Rate Function
function woocs_get_exchange_rate($from_currency, $to_currency) {
// Calculate conversion rate between currencies
...
}
What it does:
- Gets current exchange rates from WOOCS
- Calculates conversion rate between two currencies
- Used as fallback if historical rate not found
Important Notes
Historical vs. Current Exchange Rates
The code uses historical rates when possible:
$exchange_rate = get_post_meta($order_id, '_woocs_order_rate', true);
Why this matters:
- Order from 6 months ago: Used exchange rate from that date
- More accurate financial reporting
- Reflects actual revenue at time of sale
Fallback: If historical rate not available, uses current rate from WOOCS.
Performance Impact
What changes:
- ✅ Accurate multi-currency reports
- ❌ Reports may load 0.5-2 seconds slower (no cache)
- ❌ Increased database queries
Recommendation:
- Small stores (< 1,000 orders/month): Negligible impact
- Medium stores (1,000-10,000 orders/month): Minor slowdown acceptable for accuracy
- Large stores (10,000+ orders/month): Monitor performance, consider optimization
Cache Disabled
add_filter('woocommerce_analytics_enable_cache', '__return_false');
This is necessary because cached reports would show mixed currencies. The conversion happens in real-time on each report view.
Alternative approach for large stores:
- Remove cache disable line
- Clear cache manually when exchange rates change significantly
- Accept slight inaccuracy for better performance
Troubleshooting
Reports Still Show Wrong Totals
Problem: Numbers didn’t change after adding code
Solutions:
- Cache not cleared
- Make sure cache-clearing code ran
- Visit admin panel while logged in as admin
- Check if you have
manage_woocommercecapability
- Code not active
- Verify code is in functions.php (child theme)
- Or verify Code Snippets plugin has snippet activated
- Check for PHP errors in debug log
- Wrong base currency
- Verify base currency in WooCommerce → Settings → General
- Make sure WOOCS shows same base currency
Reports Loading Slowly
Problem: Analytics takes 5-10+ seconds to load
Causes:
- Large order database (10,000+ orders)
- Many currency conversions needed
- Server resources limited
Solutions:
Solution 1: Limit date range
// Only convert recent orders (last 12 months)
add_filter('woocommerce_analytics_orders_select_query', function ($results, $args) {
if (!$results || !isset($results->data)) {
return $results;
}
$twelve_months_ago = strtotime('-12 months');
foreach ($results->data as $key => $order_data) {
$order_date = strtotime($order_data['date_created']);
// Skip old orders
if ($order_date < $twelve_months_ago) {
continue;
}
// ... conversion code ...
}
return $results;
}, 10, 2);
Solution 2: Re-enable cache for specific reports Remove the cache disable line and clear cache manually when needed.
Solution 3: Use external reporting Consider dedicated analytics plugins for large stores.
Exchange Rates Not Found
Problem: Some orders show original currency, not converted
Cause: Order missing _woocs_order_rate meta and WOOCS doesn’t have that currency anymore
Solution: Add default rate mapping:
function woocs_get_exchange_rate($from_currency, $to_currency) {
global $WOOCS;
if (!isset($WOOCS) || !$WOOCS) {
// Fallback rates if WOOCS not available
$fallback_rates = [
'EUR' => 1.09, // EUR to USD
'GBP' => 1.27, // GBP to USD
'CAD' => 0.74, // CAD to USD
'AUD' => 0.66, // AUD to USD
];
if (isset($fallback_rates[$from_currency])) {
return $fallback_rates[$from_currency];
}
return 1;
}
$currencies = $WOOCS->get_currencies();
if (isset($currencies[$from_currency]) && isset($currencies[$to_currency])) {
$from_rate = floatval($currencies[$from_currency]['rate']);
$to_rate = floatval($currencies[$to_currency]['rate']);
if ($from_rate > 0) {
return $to_rate / $from_rate;
}
}
return 1;
}
Conversions Look Wrong
Problem: Converted amounts don’t match expected values
Check:
- WOOCS exchange rates accurate?
- Go to WOOCS settings
- Verify exchange rates are current
- Update rates if needed
- Order used different rate?
- Orders use rate from purchase date
- Not current rate
- This is correct behavior
- Base currency correct?
// Add debug to see what's happening error_log('Order: ' . $order_id); error_log('Currency: ' . $order_currency); error_log('Rate: ' . $exchange_rate); error_log('Original: ' . $order_data['total_sales']); error_log('Converted: ' . ($order_data['total_sales'] * $exchange_rate));
Code Breaks Site
Problem: White screen or errors after adding code
Cause: PHP syntax error or conflict
Solution:
- Access site via FTP
- Rename functions.php to functions.php.backup
- Site recovers
- Review code for syntax errors
- Check error log for specific error message
Best Practices
- Use child theme
- Always add code to child theme
- Parent theme updates won’t erase code
- Test first
- Add code on staging site first
- Verify totals match expectations
- Then apply to production
- Monitor performance
- Check Analytics load time before/after
- If too slow, consider optimizations
- Keep WOOCS rates updated
- Reports are only as accurate as exchange rates
- Update rates regularly
- Consider auto-update feature
- Document changes
- Note when you added this code
- Keep backup of functions.php
- Makes troubleshooting easier
Alternative Solutions
For Very Large Stores
If you have 50,000+ orders and this solution is too slow, consider:
- Custom database table
- Store converted values in custom table
- Update when order placed
- Query custom table for reports
- Scheduled conversion
- Convert orders daily via cron
- Store in order meta
- Fast reports with pre-converted data
- External analytics
- Export to Google Analytics with proper currency handling
- Use dedicated e-commerce analytics platform
- Third-party WooCommerce reporting plugins
For Stores with Few Currencies
If you only use 2-3 currencies, you can simplify:
// Hardcoded rates for specific currencies
add_filter('woocommerce_analytics_orders_select_query', function ($results, $args) {
if (!$results || !isset($results->data)) {
return $results;
}
$rates = [
'EUR' => 1.09,
'GBP' => 1.27,
'USD' => 1.00, // Base currency
];
foreach ($results->data as $key => $order_data) {
$order_id = $order_data['order_id'];
$order_currency = get_post_meta($order_id, '_order_currency', true);
if (isset($rates[$order_currency])) {
$rate = $rates[$order_currency];
$results->data[$key]['total_sales'] = $order_data['total_sales'] * $rate;
// ... convert other fields
}
}
return $results;
}, 10, 2);
This is faster but requires manual rate updates.
Summary
The Problem: WooCommerce Analytics adds different currencies without converting, showing incorrect totals.
The Solution: Add code that converts all orders to base currency using exchange rates from WOOCS.
Trade-offs:
- ✅ Accurate multi-currency reports
- ✅ Uses historical exchange rates
- ❌ Reports 0.5-2 seconds slower (no cache)
- ❌ Not suitable for very large stores (50,000+ orders)
Result: WooCommerce Analytics will show accurate revenue data with all orders converted to your base currency.
