=== Excelsior Currency Converter ===
Contributors: donaldanet1
Tags: woocommerce, currency, multi-currency, exchange-rates, currency-switcher
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 8.0
Stable tag: 1.6.0
WC requires at least: 7.2
WC tested up to: 11.0.1
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Real-time multi-currency display for WooCommerce. Conversion is presentational only — payments always process in your store base currency.

== Description ==

**Excelsior Currency Converter — see your prices in their currency, get paid in yours.**

* Currency switcher widget, shortcode, and block.
* Pluggable exchange rate providers: Frankfurter, European Central Bank, and exchangerate.host.
* Cached rates with stale-while-revalidate, manual refresh, and automatic refresh schedules.
* Per-currency manual rate overrides and percentage offsets.
* Unlimited supported currencies and all switcher display styles.
* "Both" display mode — base and converted prices side by side.
* Presentational-only conversion — gateways always charge your base currency.
* Order records and emails show the customer's placed currency.
* Per-currency symbol, position, decimal, and separator formatting.

= Shortcodes =
* `[excelsior_currency_converter_switcher mode="dropdown|buttons|radio|links|flags" title=""]` — the currency switcher in any format.
* `[excelsior_currency_converter_currency_code]` — the active currency ISO code.
* `[excelsior_currency_converter_currency_symbol]` — the active currency symbol.
* `[excelsior_currency_converter_convert_price amount="10" currency=""]` — convert and format a base-currency amount.
* `[excelsior_currency_converter_price_table product_id="123"]` — a product's price across every supported currency.

= Blocks =
* `Excelsior Currency Converter — Currency Switcher` — place the currency switcher anywhere blocks are supported (post content, widget areas, and site editor templates). Choose a style (dropdown, buttons, radio, links, or flags) and an optional title in the block inspector.

= Developer Hooks =
* `excelsior_currency_converter_convert_amount` — filter the converted amount (per-product / per-currency overrides).
* `excelsior_currency_converter_rounding_settings` — filter the rounding rule and charm pricing per currency.
* `excelsior_currency_converter_convert_price( $amount, $currency = '' )` / `excelsior_currency_converter_active_currency()` — template helpers.

== Installation ==

1. In your WordPress admin, go to **Plugins → Add New**, search for **Excelsior Currency Converter**, then click **Install Now**. Alternatively upload the plugin ZIP under **Plugins → Add New → Upload Plugin**.
2. Click **Activate**.
3. Go to **WooCommerce → Settings → Excelsior Currency Converter** to set your base currency, supported currencies, exchange-rate provider, refresh schedule, and switcher placement.

**Requirements:** WordPress 6.0+, PHP 8.0+, and WooCommerce 7.2+ (tested through WooCommerce 11.0.1).

== Frequently Asked Questions ==

= Will customers be charged in their own currency? =

No — conversion is presentational only. Customers see prices in their own currency, but payment gateways always charge your store's base currency. That means no currency-mismatch disputes and no surprise fees.

= Which exchange rate providers are supported? =

Frankfurter.dev and the European Central Bank need no API key; exchangerate.host needs an API key. Rates refresh manually or on an hourly, twice-daily, or daily schedule.

= Does it work with the Cart/Checkout blocks and HPOS? =

Yes. It is compatible with the WooCommerce Store API (Cart and Checkout blocks), classic checkout, and HPOS (custom order tables).

= Do order records and emails show the right currency? =

Every order stores the currency and total the customer saw at checkout. Emails are pinned to that placed currency, so invoices and support conversations stay consistent even when resent later.

== External services ==

Excelsior Currency Converter does not track visitors, serve ads, or collect personal data for marketing. It contacts only the exchange-rate provider selected by an administrator, and only when rates are manually or automatically refreshed. These requests are made by the store server, not by a shopper's browser. The provider receives the store server's IP address as part of a normal HTTP request and the requested base/target currency codes. No customer, order, cart, product, or payment data is sent.

* **Frankfurter** supplies current exchange rates. The plugin sends the base currency code when rates are refreshed. The public service requires no account or API key. Frankfurter states in its [service FAQ and privacy information](https://frankfurter.dev/#faq) that the API does not collect personal data, although its public site is behind Cloudflare. Its open-source service is provided under the [MIT license](https://github.com/lineofflight/frankfurter/blob/main/LICENSE); it does not publish a separate terms-of-service page.
* **European Central Bank (ECB)** supplies daily euro reference rates. The plugin downloads the ECB's public XML feed when rates are refreshed; no currency, customer, or store data is added to the request. See the ECB [disclaimer and copyright terms](https://www.ecb.europa.eu/services/using-our-site/disclaimer/html/index.en.html) and [website privacy statement](https://www.ecb.europa.eu/services/data-protection/privacy-statements/html/ecb.privacy_statement_website.en.html).
* **exchangerate.host** supplies current exchange rates when selected. The plugin sends the administrator's API key, base currency code, and target currency codes when rates are refreshed. See exchangerate.host's [terms of use](https://exchangerate.host/terms) and [privacy policy](https://exchangerate.host/privacy).

If no provider is selected or no refresh occurs, the plugin makes no exchange-rate request. Provider use is subject to the linked provider policies.

**Data stored locally:** exchange rates are cached in WordPress transients; your currency preference is saved in a browser cookie / `localStorage`; order records store the displayed currency and exchange rate. Nothing is shared with third parties other than the provider calls described above.

**Bundled assets:** the currency flag icons come from the [flag-icons](https://github.com/lipis/flag-icons) project (MIT license, GPL-compatible) and are served locally from this plugin — no external image requests.

== Screenshots ==

1. Homepage with the Excelsior Currency Converter currency switcher.
2. Shop prices converted to the visitor's currency.
3. The currency switcher, open with flags.
4. Excelsior Currency Converter settings tab — General.
5. Exchange rate provider settings.
6. Manual rates and offsets.

== Changelog ==

= 1.6.0 =
* Made per-currency price formatting fully available: its service now loads and registers, settings are rendered in WooCommerce, and values are sanitized and persisted.
* Automatic hourly, twice-daily, and daily exchange-rate refresh schedules are available alongside manual refresh.
* Removed edition upsells, unavailable-feature descriptions, runtime edition gates, and references to absent edition-specific classes from the normal package.
* Retained encrypted API-key storage and hardened generated price markup from the 1.5 release.

= 1.5.0 =
* API keys are now encrypted before they are stored in the settings option.
* Fixed: clearing the API key field now also removes the cached per-provider key, so the previously saved key is no longer silently reused.
* Hardened shortcode and order-note output with `wp_kses_post` so generated price markup is always sanitized before rendering.

= 1.4.0 =
* Fixed the flags-style dropdown changing the navbar height when opened: the dropdown list is now forcibly absolutely positioned (`!important`) so it overlays the page instead of being pulled into the menu's flow by theme rules like Astra's `.main-navigation ul { position: relative }`.
* Switcher CSS/JS are now enqueued with file-modified-time versions so style/script changes are never served stale from the browser cache.
* Reworked the header switcher placement: the “Site header” option now places the currency switcher in the navigation menu, appended after the last item (e.g. after “Checkout”), so it is reliably visible on any theme instead of trying to sit beside the page title.
* Redesigned the switcher UI: dropdown, buttons, radio, and links formats now share the polished pill/segmented look of the flags style, and each currency shows its flag. Buttons render as a segmented control, radio as pill chips with a custom indicator, and links as pill chips with the active currency highlighted.
* Fresh-install defaults: base currency follows the store's WooCommerce currency; supported currencies default to EUR, GBP, USD; provider defaults to the European Central Bank; manual-rate and offset rows are pre-seeded for each supported currency; switcher placement defaults to floating bottom-left with the flags style; rounding is off and display mode is converted-only.
* Added a new switcher placement: “Site header — next to the page title”, which shows the currency switcher beside the site title on any theme (previously the header placement only worked on Storefront).
* Added the European Central Bank as a free exchange-rate provider (no API key required).
* Added per-currency manual rate overrides and percentage offsets in the Excelsior Currency Converter settings tab.
* Added per-currency price formatting for symbols, positions, decimals, and separators.

= 1.3.7 =
* Order totals are now converted for display everywhere a customer sees a figure: order-received (thank you), order-pay, My Account order details, and order emails. Previously stored orders showed the base amount under the active-currency symbol (e.g. £149 instead of the converted amount); the amount and symbol are now always consistent.
* Cart/Checkout block orders now record the displayed currency and exchange rate (the Store API never fires the classic checkout-create hook, so the order meta was never saved for block checkouts).

= 1.3.6 =
* Replaced platform-dependent flag emoji with bundled local SVG flags so the flags switcher renders consistently on Windows, Cart, and Checkout without external requests.

= 1.3.4 =
* Fixed a late WooCommerce Blocks hydration race that could overwrite the cleared cart snapshot with base-currency data. Cart and Checkout now validate the registered cart store and refetch until its currency matches the active display currency.

= 1.3.3 =
* Fixed stale base-currency cart amounts reappearing when navigating between Cart and Checkout. Browser history restores now clear persisted snapshots and immediately refresh the WooCommerce Blocks cart store, without the previous unconditional second page load.

= 1.3.2 =
* Fixed the Cart and Checkout blocks showing base-currency amounts under the active-currency symbol on first load. The blocks preload cart data through an internal REST dispatch that bypassed the previous conversion hook; conversion now runs on `rest_request_after_callbacks`, which also covers preloaded and batched requests. Conversion is now idempotent so no amount is ever converted twice.

= 1.3.1 =
* Fixed the flags-style switcher toggle text becoming invisible on hover by using an explicit text color instead of inheriting the theme's.

= 1.3.0 =
* Renamed the plugin to Excelsior Currency Converter. Internal settings, cached exchange rates, and stored data are unchanged.
* Fixed converted prices in the Cart and Checkout blocks when data loads through the Store API `batch` endpoint (amounts could appear in the base currency with the active currency symbol).
* "Both" display mode now shows the base price with the base currency symbol.
* The currency switcher now shows each currency's own symbol regardless of the active currency.

= 1.2.0 =
* Security: currency switching now runs only through the nonce-verified handler; removed the unauthenticated switch path.
* Fixed automatic refresh intervals not saving.
* Rounding is applied consistently across classic and Blocks, and charm pricing no longer touches tax, shipping, or fee amounts.
* Stored order totals (account, order-received, emails) are no longer re-converted.
* Added `[excelsior_currency_converter_currency_code]`, `[excelsior_currency_converter_currency_symbol]`, `[excelsior_currency_converter_convert_price]`, and `[excelsior_currency_converter_price_table]` shortcodes.
* Added `radio` and `links` switcher formats.
* Added `excelsior_currency_converter_convert_amount` and `excelsior_currency_converter_rounding_settings` filters plus `excelsior_currency_converter_convert_price()` / `excelsior_currency_converter_active_currency()` helpers.
* Added a Currency Converter section to WooCommerce → Status → System status.
* Added a Switcher placement setting: site header, any screen corner (floating), manual-only, or hidden from visitors (admin-only currency control).
* Added a Switcher style setting including a Flags style (country flag + code + symbol) with a `excelsior_currency_converter_currency_flag_html` filter for image flags.

= 1.1.1 =
* Inject an early inline script that clears the WooCommerce Blocks cart snapshot before `wc/store/cart` registers.
* Add `Cache-Control: no-store` + `Vary: excelsior_currency_converter_currency` to Cart and Checkout pages when the active currency differs from base, preventing bfcache / disk-cache from replaying stale base values.
* Move runtime URL parsing inside `DOMContentLoaded` so the switcher IIFE no longer throws `document is not defined` on early-included pages.

= 1.1.0 =
* Forced a fresh Store API cart response on Cart/Checkout pages when the display currency differs from the base.

= 1.0.9 =
* Kept WooCommerce payment currency and shipping calculations in base currency.
* Added Cart and Checkout Blocks disclaimer support.
* Improved multisite uninstall, cron cleanup, and cart-fragment refresh behavior.

= 1.0.8 =
* Hardened Store API conversion and currency-aware cart cache handling.
* Updated compatibility metadata and cleanup behavior.

= 1.0.0 =
* Initial release.

== Upgrade Notice ==

= 1.6.0 =
Per-currency formatting and automatic refresh schedules are fully available in the normal plugin, with cleaner edition separation and no runtime feature gates.

= 1.5.0 =
API credentials are encrypted at rest and generated price markup is sanitized before rendering.

= 1.4.0 =
A unified pill/segmented switcher design, scheduled rate refresh, a European Central Bank provider, manual rate overrides, and per-currency price formatting. Review the changelog before upgrading.
