FOX - WooCommerce Currency Switcher Professional

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

  1. Go to WooCommerce → Analytics → Revenue
  2. Check your sales totals
  3. Compare with previous (incorrect) data
  4. 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:

  1. Cache not cleared
    • Make sure cache-clearing code ran
    • Visit admin panel while logged in as admin
    • Check if you have manage_woocommerce capability
  2. 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
  3. 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:

  1. WOOCS exchange rates accurate?
    • Go to WOOCS settings
    • Verify exchange rates are current
    • Update rates if needed
  2. Order used different rate?
    • Orders use rate from purchase date
    • Not current rate
    • This is correct behavior
  3. 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:

  1. Access site via FTP
  2. Rename functions.php to functions.php.backup
  3. Site recovers
  4. Review code for syntax errors
  5. Check error log for specific error message

Best Practices

  1. Use child theme
    • Always add code to child theme
    • Parent theme updates won’t erase code
  2. Test first
    • Add code on staging site first
    • Verify totals match expectations
    • Then apply to production
  3. Monitor performance
    • Check Analytics load time before/after
    • If too slow, consider optimizations
  4. Keep WOOCS rates updated
    • Reports are only as accurate as exchange rates
    • Update rates regularly
    • Consider auto-update feature
  5. 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:

  1. Custom database table
    • Store converted values in custom table
    • Update when order placed
    • Query custom table for reports
  2. Scheduled conversion
    • Convert orders daily via cron
    • Store in order meta
    • Fast reports with pre-converted data
  3. 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.