Multi-currency auto-conversion
Sell in EUR, USD and GBP, report all of them in one currency. Beaconry hooks into the dispatch pipeline and rewrites value + every items[].price into your chosen target currency before the event leaves your server, using ECB Daily Rates pulled once per day.
What it does
If your shop accepts multiple currencies (WooCommerce Multi-Currency, Aelia, manual switcher, geo-routing) you face the same reporting problem on every ad platform: Meta wants one reporting currency, Google Ads wants one reporting currency, your CFO wants one reporting currency. Without normalisation you get conversion totals split across three buckets that you then add up in a spreadsheet, with FX rates from whatever moment Meta happened to pick.
Multi-currency normalises every transaction in flight. The original currency stays on the event as an internal annotation so your debug logs and the live dashboard can still show "92.59 EUR (USD)" if you want to know what was actually charged.
How to enable
wp-admin, Beaconry, Advanced tab, Multi-Currency reporting card. Pick a target currency from the dropdown (any of the ~30 ECB-published codes). Save. Default is "Disabled", which passes events through unchanged.
Power-user override: set BCNR_CURRENCY_TARGET in wp-config.php to lock the target across deploys, see "Constants for power-users" below.
How it works (under the hood)
- Daily ECB pull. A WP-Cron event
bcnr_currency_refreshfetches the European Central Bank Daily Rates XML fromhttps://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml(5-second timeout, official trusted source). The parsed[code => rate]table is cached in two places: a 24-hour transientbcnr_fx_ratesfor fast reads and a durableautoload=falseoptionbcnr_fx_rates_fallbackthat survives a transient eviction. - Pre-dispatch filter.
BCNR_Currency::normalize_event()hooks thebcnr_pre_dispatch_eventfilter at priority 10. It runs once per event, before fan-out to channels, so every channel sees the same already-normalised value. - Cross-currency math via EUR bridge. ECB publishes only EUR-to-X rates. To convert USD → GBP, Beaconry goes USD → EUR (1 / rate[USD]) → GBP (× rate[GBP]). Same-currency events are a no-op pass-through, unknown-currency events are a no-op pass-through (no silent guessing on a typo).
- Annotation on the event. After conversion,
_bcnr_fx_source(original ISO code) and_bcnr_fx_rate(rate applied) are added to the event payload. Internal fields, stripped before HTTP send by each channel'sdispatch_*method (only documented Meta / GA4 / TikTok / LinkedIn / Google-Ads keys go on the wire). Visible in the live dashboard's recent-events table and inbcnr_logon dispatch failures. - Outage handling. ECB occasionally hiccups around 16:00 CET (their own daily publish window). If the pull fails, Beaconry falls back to the durable cache (last successful pull, often hours old, FX rates change at most fractions of a percent per day). If the durable cache is empty too (fresh install during an ECB outage), the filter passes events through unchanged with the original currency, and an admin notice flag
bcnr_fx_last_erroris set so the next page-load shows the operator what happened. Dispatch never crashes.
Constants for power-users
BCNR_CURRENCY_TARGET in wp-config.php, value is a 3-letter ISO-4217 code (uppercase). When set, the constant wins over the DB setting at read time, the dropdown in the UI is shown locked with a hint pointing back to wp-config.php. Useful for staging-vs-production parity, infra-as-code deploys, and for the rare case where you want a non-listed currency that's not in the ECB feed (the constant accepts any ISO code, the conversion still requires both source and target to be ECB-known though).
Troubleshooting
- "My values look unchanged": most likely the source currency is empty on the event (non-monetary event like
page_view) or matches the target. Both are no-op cases by design. Check the live dashboard recent-events table, the converted event would show_bcnr_fx_source+_bcnr_fx_rateannotations. - "Admin notice says ECB unreachable": ECB outage. Beaconry will retry on the next cron tick and self-recover. Existing events kept their original currency in the meantime, no data was lost. If the notice persists for more than a day, check that
wp_remote_getcan reachwww.ecb.europa.eufrom your server (firewall, outbound HTTP). - "I picked a target currency, the dropdown is now disabled":
BCNR_CURRENCY_TARGETis defined inwp-config.php. Constant wins over the DB setting. Either editwp-config.phpor delete the constant if you want the UI to control it. - "Can I use a custom rate": not currently exposed. The intent of multi-currency is "one trusted public source, no operator surprise". If you need a hand-rolled rate per market, hook
bcnr_pre_dispatch_eventyourself at priority 9 (before Beaconry's 10) and rewritevalue+currencythere.