Troubleshooting
Common issues with FCHub Multi-Currency and how to resolve them. Covers price projection problems, exchange rate failures, switcher issues, checkout disclosure, and FluentCRM sync.
Prices Not Converting
Check that the master switch is on: FluentCart > Settings > Multi-Currency > General > Enabled. When disabled, no frontend output happens at all — no projection, no switcher, no disclosure.
The plugin needs at least one display currency to do anything useful. Go to the Currencies tab and add currencies. Once one is configured, FluentCart's base currency is included in the switcher automatically.
If rates haven't been fetched yet, the plugin has nothing to convert with. A non-base selection is rejected before it is saved, so it cannot appear to work and then jump back on the next page. Check the Exchange Rates tab — if the rates table is empty, click Refresh Now or wait for the cron job. If the refresh fails, check your API key and provider settings.
The price projection engine is JavaScript. If another plugin or theme throws a JS error before the projection script runs, it may never execute.
Debug steps:
- Open browser developer tools (F12)
- Check the Console tab for JavaScript errors
- Look for errors before
fchub-mc-projectionloads - Try disabling other plugins temporarily to isolate conflicts
The js_projection feature flag controls whether the projection script is enqueued. Check Diagnostics tab — if js_projection shows false, the script is disabled. This flag is stored in fchub_mc_feature_flags option and can be toggled via wp_options.
If you've switched to EUR but prices still show in USD, the context resolution may be failing. Check:
- Browser persistence blocked — verify the
fchub_mc_currencycookie or local-storage entry exists. Both carry the same confirmed three-letter code; if the browser blocks both, there is nowhere to remember a guest choice. - Recovery request blocked — cached pages are repaired through
GET /fchub-mc/v1/context?currency=EUR, which does not depend on the cookie reaching WordPress. Check the Network tab for a failed request. - Old HTML still cached after an update — purge the page or edge cache once so it serves the current recovery runtime. Per-page cache exclusions are not required after that.
Exchange Rate Issues
The rate refresh depends on WordPress cron. If your site has low traffic, WP-Cron may not fire on time.
Fix: Set up a system cron:
*/10 * * * * curl -s https://yoursite.com/wp-cron.php > /dev/null 2>&1Also check that the cron event is scheduled: look for fchub_mc_refresh_rates in a cron inspector plugin like WP Crontrol.
The Refresh Now button calls POST /fchub-mc/v1/admin/rates/refresh for remote providers. If it returns 409, Manual rates is the saved provider; use Save Manual Rates instead.
If it returns 500:
- API key invalid — check your rate provider API key in settings
- Provider down — the external API may be temporarily unavailable
- Lock contention — another refresh is already running (120-second lock). Wait and try again
- Empty rates — the provider returned no rates. Check your base currency is supported by the provider
- Incomplete snapshot — the provider does not cover one of your configured display currencies. Remove that currency or use a provider that supports the complete set
- Persistence failure — the database rejected the snapshot. The previous rates remain active; check the FluentCart logs for the database error
A yellow admin notice appears when any rate exceeds the stale threshold. This means the cron job hasn't successfully refreshed rates recently.
Common causes:
- WP-Cron not running (see above)
- API key expired or rate-limited
- Provider returning errors
- The cron event was unscheduled (try deactivating and reactivating the plugin)
The ECB provider publishes EUR-based rates only. If your base currency is USD, the plugin cross-rates by dividing. This requires the bcmath PHP extension for precision.
Without bcmath, the plugin uses native PHP float division, which can introduce tiny rounding errors (e.g. 0.92139999 instead of 0.92140000). These are usually insignificant for display purposes, but if precision matters, install bcmath.
Also note: ECB rates update once daily around 16:00 CET. A 1-hour refresh interval won't get you fresher data.
Currency Switcher Issues
- Block or shortcode placed? — make sure the Currency Switcher block or
[fchub_currency_switcher]shortcode is in content that actually renders on the current page - Plugin disabled? — the block and shortcode both return empty when the plugin is off
- No display currencies? — the block and shortcode both return empty when no currencies are configured
- Theme conflict — check if another element is overlapping the switcher (z-index issue). The dropdown uses
z-index: 9999
The dropdown is controlled by JavaScript. If the script fails to initialise:
- Check browser console for JS errors
- Look for the
data-fchub-mc-enhancedattribute on the switcher element — if it's missing, the init script didn't run - Try calling
window.fchubMcInitSwitchers()from the console to manually trigger initialisation
Prices change when you select a currency, but the old one is back on the next page.
The switch itself needs nothing from the server, so this is always about where the preference is kept rather than whether it was applied.
- Browser persistence blocked — the choice is stored in local storage and mirrored to the
fchub_mc_currencycookie. Some privacy plugins and browser settings block both, which leaves nothing to remember it by - Cookie persistence disabled — check Settings → Cookie Persistence. With it off, a logged-out visitor's choice deliberately lasts only for the page they are on
POST /contextfailing — the preference reaches emails, order metadata and CRM through this request. A firewall rule blocking WordPress REST requests leaves the visitor with correct prices and a preference that does not outlive the session; the browser console says so when it happens- Account request rejected — signed-in visitors use the current WordPress REST nonce. Reload a genuinely old account page if its nonce has expired; guest requests intentionally send no nonce.
The fallback form submits without JavaScript, but it still needs some persistence path.
- Cookies disabled for guests — if guest cookies are disabled in plugin settings, a guest visitor has nowhere to store the preference after the request completes
- Form blocked by aggressive HTML filtering — some builders or security plugins strip
<noscript>or form markup
A stale cached nonce no longer blocks guests: their submission writes only their own cookie, so the form accepts it however old the cached page is. Signed-in submissions still require a fresh nonce, and signed-in pages are rendered fresh.
The badge uses WordPress's human_time_diff() with the site's configured timezone. If the time seems off:
- Check your WordPress timezone: Settings > General > Timezone
- The
fetched_atcolumn stores timestamps in WordPress site timezone. If your site timezone changed after rates were fetched, the diff may look wrong
Checkout Disclosure Issues
The disclosure only appears when the display currency differs from the base currency. If you're viewing prices in the base currency, there's nothing to disclose.
Also check:
- Setting enabled —
checkout_disclosure_enabledmust beyes - JavaScript running — the disclosure is injected via the projection script. JS errors may prevent it
- FluentCart checkout element present — the script looks for
.fct_summary_boxto inject after
If you've set custom text in settings but still see the generic fallback:
- Verify the text is saved — check the Checkout tab
- The custom text is passed to JavaScript via
fchubMcConfig.disclosureText. Check if this value is populated in the page source - The fallback triggers when
disclosureTextis empty or null
FluentCRM Sync Issues
- FluentCRM active? — the sync only fires when
defined('FLUENTCRM')is true - Sync enabled? — check
fluentcrm_enabledandfluentcrm_auto_create_tagsin settings - Guest user — tag sync only fires for logged-in users. Guests have no FluentCRM contact
- Contact exists? — the plugin looks up the contact by WordPress user ID. If no FluentCRM contact exists for the user, sync is skipped
The custom field keys must exist as FluentCRM custom fields. If the field key doesn't match a configured custom field in FluentCRM, the syncCustomFieldValues() call silently does nothing.
Fix: Go to FluentCRM > Contacts > Custom Fields and create text fields with the exact key names from your settings (default: preferred_currency, last_order_display_currency, last_order_fx_rate).
Caching and Optimisation
No. Every storefront page this plugin touches is byte-identical for every visitor, including the switcher markup and the configuration the browser reads. There is nothing per-visitor in a cached document to get wrong, so:
- no cookie exclusions,
- no per-page exclusions for pages carrying a switcher,
- no query-string cache rules for
?currency=.
The visitor's currency lives in their own browser and is applied before the first paint. A shared cache can serve the same bytes to everyone, which is what it is for.
The one piece that must not be deferred is the inline block in the document head — it carries the currency table and decides which currency to show before anything paints. It is inline rather than a file for exactly that reason, so most tools leave it alone. If yours does not:
- WP Rocket — add
fchub-mc-bootstrapto Delay JavaScript execution exclusions. - LiteSpeed Cache — add it to JS Excludes.
- Perfmatters — add it to the Delay JavaScript exclusions list.
You should not need a CSS safelist. The rules that govern the moment before prices appear are inline in the head with the script, not in a stylesheet an unused-CSS pass can reach.
That is the plugin's failure mode when its JavaScript never runs, and it is deliberate: the amount you see is the amount you are charged. Check the browser console for errors, then check whether an optimisation plugin is delaying the inline head block above.
Performance Issues
The plugin's frontend impact is minimal, and switching currency makes no request at all — the browser already holds every rate the page offers. If you notice slowness:
- Rate cache miss — without persistent object cache (Redis/Memcached), every page load queries the database for rates. Install a persistent cache for sub-millisecond lookups
- MutationObserver thrashing — if your page has extremely frequent DOM mutations, the 50ms debounce may still cause excessive projection runs. This is very rare in practice
- A very large currency list — the page carries every selectable currency. Fifty currencies is about half a kilobyte compressed, so this is rarely the cause, but a store offering all of them pays a little more per page than one offering five
The cron job prunes rows older than 90 days. If the table is still large, you have many currency pairs being tracked.
For example: 10 display currencies × 1 base = 10 pairs. At 4 refreshes per day over 90 days = 3,600 rows. At 30 currencies, that's 10,800 rows — still very manageable.
If you're concerned, you can manually prune:
DELETE FROM wp_fchub_mc_rate_history WHERE fetched_at < DATE_SUB(NOW(), INTERVAL 30 DAY);Debug Tips
Diagnostics Tab
Your first stop for any issue: FluentCart > Settings > Multi-Currency > Diagnostics. It shows plugin version, PHP version, bcmath availability, FluentCart/FluentCRM status, rate count, stale currencies, and feature flags.
General debugging steps:
- Check Diagnostics tab — most status information is there
- Check browser console — JS errors, failed REST calls, cookie issues
- Check browser Network tab — look for failing
/fchub-mc/v1/requests - Verify cron is running — install WP Crontrol and check for
fchub_mc_refresh_rates - Enable WP_DEBUG_LOG — the plugin logs errors to WordPress's debug log via its internal logger
- Check
wp_options— look atfchub_mc_settings,fchub_mc_feature_flags, andfchub_mc_db_version
If you need to report an issue, include:
- Diagnostics tab output
- Browser console errors
- WordPress and PHP versions
- Whether you're using a persistent object cache