Exchange Rates
PerfLocale can automatically fetch live exchange rates and keep your per-language currency configuration up to date.
Quick Start
- Go to PerfLocale > Settings > WooCommerce
- Enable Per-Language Currency
- Configure a currency code for each language
- Enable Auto-Sync Rates
- Select a provider and sync interval
- Click Sync Now to verify
Providers
Frankfurter (Free, default)
- Source: European Central Bank (ECB) reference rates
- API Key: Not required
- Limits: No rate limits
- Base currencies: All major currencies
- URL:
api.frankfurter.app - Data sent: base + symbol currency codes only (e.g.
?base=USD&symbols=EUR,GBP). No user data, no WordPress identity, no personally identifiable information. - License / Terms: MIT License - open-source, no formal privacy policy because no personal data is collected.
- Docs: frankfurter.dev
- Notes: Rates update once per business day (ECB schedule). Best for daily or weekly sync.
ExchangeRate-API (Free)
- Source: Multiple central banks
- API Key: Not required for the free tier
- Limits: ~1,500 requests/month
- Base currencies: All supported currencies
- URL:
open.er-api.com - Notes: Good general-purpose provider. Rates update daily.
Open Exchange Rates (Freemium)
- Source: Aggregated market data
- API Key: Required (sign up)
- Free tier: 1,000 requests/month, USD base only
- Paid tiers: All base currencies, hourly updates
- URL:
openexchangerates.org - Notes: Free tier only supports USD as base currency. PerfLocale automatically cross-calculates rates for other base currencies, but accuracy may vary slightly.
CurrencyFreaks (Freemium)
- Source: Aggregated market data
- API Key: Required (sign up)
- Free tier: 1,000 requests/month
- Base currencies: Configurable
- URL:
api.currencyfreaks.com
Fixer.io (Paid, HTTPS)
- Source: European Central Bank + 15 other sources
- API Key: Required (sign up)
- Plan: Paid plan required - PerfLocale uses HTTPS exclusively, which is only available on paid Fixer.io plans
- Paid tiers: All base currencies, HTTPS, hourly updates
- URL:
data.fixer.io - Notes: Free tier only supports EUR base and HTTP (no HTTPS). PerfLocale requires HTTPS for all API calls, so a paid plan is necessary. PerfLocale cross-calculates rates for non-EUR base currencies.
Sync Intervals
| Interval | Requests/day | Requests/month |
|---|---|---|
| Every Hour | 24 | ~720 |
| Every 2 Hours | 12 | ~360 |
| Every 4 Hours | 6 | ~180 |
| Every 6 Hours | 4 | ~120 |
| Every 8 Hours | 3 | ~90 |
| Every 12 Hours | 2 | ~60 |
| Once Daily (default) | 1 | ~30 |
| Once Weekly | ~0.14 | ~4 |
| Once Monthly | ~0.03 | 1 |
Choose an interval that fits within your API plan limits. For most stores, daily is sufficient since exchange rates don't change drastically within a day.
API Key Management
Database (Settings UI)
Enter the key in the Settings page. The key is stored in the perflocale_settings option.
Important: Keys stored in the database are excluded from export/import to prevent accidental leakage. If you export settings and import them on another site, you must re-enter API keys.
wp-config.php Constants (Recommended for production)
Define the key as a PHP constant in wp-config.php for security. When a constant is defined, it takes priority and the field in the UI shows the constant name instead of an input.
// Open Exchange Rates
define( 'PERFLOCALE_OXR_API_KEY', 'your-api-key-here' );
// CurrencyFreaks
define( 'PERFLOCALE_CURRENCYFREAKS_KEY', 'your-api-key-here' );
// Fixer.io
define( 'PERFLOCALE_FIXER_KEY', 'your-api-key-here' );
Benefits of using constants:
- Not stored in the database (not exposed in exports, backups, or SQL dumps)
- Not visible in the WordPress admin UI
- Can differ per environment (staging vs production)
- Cannot be changed by other plugins or admin users
Custom Provider via Filter
Register your own exchange rate provider using the perflocale/woocommerce/exchange_rate_providers filter:
add_filter( 'perflocale/woocommerce/exchange_rate_providers', function( array $providers ): array {
$providers['my_custom_api'] = [
'name' => 'My Custom API',
'needs_key' => true,
'key_setting' => 'wc_my_custom_key',
'fetch_callback' => function( string $base_currency, array $target_currencies, string $api_key ): array {
$response = wp_remote_get( 'https://my-api.example.com/rates?base=' . $base_currency . '&key=' . $api_key );
if ( is_wp_error( $response ) ) {
return [];
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
$rates = [];
foreach ( $target_currencies as $code ) {
if ( isset( $body['rates'][ $code ] ) ) {
$rates[ $code ] = (float) $body['rates'][ $code ];
}
}
return $rates;
},
];
return $providers;
} );
To also support a wp-config.php constant for the custom API key, add it to the settings constant map:
add_filter( 'perflocale/settings/constant_map', function( array $map ): array {
$map['wc_my_custom_key'] = 'MY_CUSTOM_API_KEY';
return $map;
} );
Then define in wp-config.php:
define( 'MY_CUSTOM_API_KEY', 'your-key-here' );
Hooks Reference
Filters
perflocale/woocommerce/exchange_rate_providers
Modify or add exchange rate providers.
add_filter( 'perflocale/woocommerce/exchange_rate_providers', function( $providers ) {
// Remove a built-in provider
unset( $providers['fixer'] );
// Add a custom provider (see example above)
$providers['my_api'] = [ ... ];
return $providers;
} );
perflocale/woocommerce/exchange_rates_fetched
Filter rates after they are fetched but before they are saved.
add_filter( 'perflocale/woocommerce/exchange_rates_fetched', function( array $rates, string $base, string $provider ): array {
// Add a margin to all rates
foreach ( $rates as $code => $rate ) {
$rates[ $code ] = $rate * 1.02; // 2% markup
}
return $rates;
}, 10, 3 );
Actions
perflocale/woocommerce/exchange_rates_synced
Fires after rates are successfully saved.
add_action( 'perflocale/woocommerce/exchange_rates_synced', function( array $rates, string $base, string $provider ): void {
// Log the sync
error_log( sprintf( 'Exchange rates synced from %s: %s', $provider, wp_json_encode( $rates ) ) );
// Clear page cache
if ( function_exists( 'wp_cache_flush' ) ) {
wp_cache_flush();
}
}, 10, 3 );
Troubleshooting
Rates not updating
- Check that WP-Cron is running. Some hosts disable WP-Cron; you may need a server-side cron job:
*/5 * * * * curl -s https://example.com/wp-cron.php > /dev/null 2>&1 - Click Sync Now in the settings to test manually.
- Enable
WP_DEBUGandWP_DEBUG_LOGinwp-config.phpto see sync errors:
Checkdefine( 'WP_DEBUG', true ); define( 'WP_DEBUG_LOG', true );wp-content/debug.logfor lines starting withPerfLocale Exchange Rate Sync:.
"API key missing" error
Ensure the key is either:
- Entered in the Settings UI, or
- Defined as a constant in
wp-config.php
The constant takes priority. If defined as a constant, the UI field is disabled.
Rates differ from expected
- Free API tiers may return rates from the previous day.
- Cross-calculation (when the API base differs from your store base) introduces minor rounding.
- Some providers have different data sources; rates may vary slightly between providers.
"No rates returned" error
- The API may be temporarily unavailable. Try again or switch providers.
- Check that your target currency codes are valid ISO 4217 codes (e.g., EUR, GBP, JPY).
- Free tiers may restrict certain currencies.