本文约 5,224 字,预计阅读 14 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:客户看到的价格,首先要”可信”
外贸站展示多币种,动机通常是好的:让美国客户看到美元、欧洲客户看到欧元,降低换算成本。但落地时经常出问题:汇率是手动填的,三个月没更新,客户一算发现比市场价高 8%;或者切换币种后购物车价格对不上,结账时又跳回美元,客户以为被套路。价格是信任的最后一道防线,一旦客户觉得你的报价”不准”,前面的所有努力都白费。所以多币种的核心不是”能切换”,而是”汇率可信、全程一致、边界清晰”。
原理分析:B2B 与 B2C 的币种需求完全不同
B2C 零售必须实时结算:客户用美元下单,就用美元扣款,所以必须接多币种支付通道,价格与结算货币一致。
B2B 询盘则不同:绝大多数订单走电汇,币种只是”报价参考”。这时做实时汇率反而是负担——汇率每天都在动,你今天报 100 美元,客户下周才下单,价格可能已经变了。B2B 更常见的做法是:以美元为基准报价,页面展示一个”参考汇率”换算的本地货币,并明确标注”仅供参考,最终以确认单为准”。
| 场景 | 币种策略 | 是否需要实时汇率 |
|---|---|---|
| B2C 零售 | 客户币种结算 | 必须 |
| B2B 询盘 | 基准币种报价 + 参考换算 | 建议,但需标注 |
| 批发议价 | 只展示基准币种 | 不需要 |
WooCommerce 提供了两个关键过滤器:woocommerce_currency 用于切换当前显示的货币代码,woocommerce_product_get_price 用于在读取价格时做换算。这两个过滤器配合,就能实现一套不依赖插件的轻量切换,非常适合 B2B 展示型需求。
保姆级实操
步骤 1:确定基准货币。 在”WooCommerce → Settings → General”里把 Currency 设为 USD(或你的实际结算币种)。所有价格以后都按这个币种录入。
步骤 2:存汇率。 汇率不要写死在代码里,存进 option,用每日定时任务更新。
# 每日更新汇率到 option(由系统 cron 触发)
wp cron event list --fields=hook,next_run --format=table
wp option get mmf_fx_rates
步骤 3:拉取并缓存汇率。 用 WordPress 的 HTTP API,失败时保留上一次的值,绝不因为接口挂掉就显示错误价格。
function mimangfei_refresh_fx_rates() {
$base = 'USD';
$symbols = 'EUR,GBP,JPY,AUD,CAD';
$url = 'https://api.exchangerate.host/latest?base=' . $base . '&symbols=' . $symbols;
$response = wp_remote_get( $url, array( 'timeout' => 10 ) );
if ( is_wp_error( $response ) ) {
return false;
}
$code = wp_remote_retrieve_response_code( $response );
if ( 200 !== $code ) {
return false;
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( empty( $body['rates'] ) || ! is_array( $body['rates'] ) ) {
return false;
}
$rates = array_map( 'floatval', $body['rates'] );
$rates['USD'] = 1.0;
update_option( 'mmf_fx_rates', $rates );
update_option( 'mmf_fx_updated', current_time( 'mysql' ) );
return true;
}
步骤 4:注册每日更新任务。
if ( ! wp_next_scheduled( 'mmf_daily_fx_update' ) ) {
wp_schedule_event( strtotime( '02:30:00' ), 'daily', 'mmf_daily_fx_update' );
}
add_action( 'mmf_daily_fx_update', 'mimangfei_refresh_fx_rates' );
步骤 5:实现币种切换。 用 cookie 记住用户选择,再用 woocommerce_currency 过滤器切换显示币种。
add_filter( 'woocommerce_currency', 'mimangfei_switch_currency' );
function mimangfei_switch_currency( $currency ) {
$allowed = array( 'USD', 'EUR', 'GBP', 'JPY', 'AUD', 'CAD' );
$picked = isset( $_COOKIE['mmf_currency'] ) ? strtoupper( sanitize_key( $_COOKIE['mmf_currency'] ) ) : '';
if ( in_array( $picked, $allowed, true ) ) {
return $picked;
}
return $currency;
}
步骤 6:换算价格。 用 woocommerce_product_get_price 过滤器,按汇率换算并按币种做尾数取整(日元没有小数,美元保留两位)。
add_filter( 'woocommerce_product_get_price', 'mimangfei_convert_price', 10, 2 );
function mimangfei_convert_price( $price, $product ) {
if ( '' === $price || ! is_numeric( $price ) ) {
return $price;
}
$rates = (array) get_option( 'mmf_fx_rates', array() );
$target = apply_filters( 'woocommerce_currency', get_option( 'woocommerce_currency' ) );
$base = 'USD';
if ( $target === $base || empty( $rates[ $target ] ) ) {
return $price;
}
$converted = (float) $price * (float) $rates[ $target ];
// 按币种处理小数位与尾数
if ( in_array( $target, array( 'JPY' ), true ) ) {
return ceil( $converted );
}
return round( $converted, 2 );
}
步骤 7:处理缓存冲突。 这是最容易出错的一环:同一 URL 对不同币种返回不同价格,页面缓存会把美元版本发给选了欧元的客户。解决方案是按币种做缓存变体——把币种写进 cookie 并在缓存层按该 cookie 区分。
# 按币种 cookie 区分缓存变体
map $http_cookie $mmf_currency_key {
default "usd";
"~*mmf_currency=EUR" "eur";
"~*mmf_currency=GBP" "gbp";
"~*mmf_currency=JPY" "jpy";
}
步骤 8:展示汇率更新时间与免责声明。 在价格下方小字标注 “Converted at 1 USD = X EUR, updated 2026-01-01. For reference only.”,这句声明能消除绝大部分争议。
add_action( 'woocommerce_single_product_summary', 'mimangfei_fx_notice', 31 );
function mimangfei_fx_notice() {
$rates = (array) get_option( 'mmf_fx_rates', array() );
$updated = get_option( 'mmf_fx_updated' );
$target = apply_filters( 'woocommerce_currency', get_option( 'woocommerce_currency' ) );
if ( 'USD' === $target || empty( $rates[ $target ] ) || ! $updated ) {
return;
}
printf(
'<p class="fx-note">Converted at 1 USD = %s %s (updated %s). For reference only.</p>',
esc_html( number_format( (float) $rates[ $target ], 4 ) ),
esc_html( $target ),
esc_html( mysql2date( 'Y-m-d', $updated ) )
);
}
步骤 9:B2C 场景用现成插件。 如果确实需要多币种结算,用 WooCommerce 官方的 WooCommerce Payments、或 WPML 的 WooCommerce Multilingual & Multicurrency、Aelia Currency Switcher 这类成熟方案,不要自研结算逻辑。
常见踩坑
- 汇率长期不更新。 客户发现价格偏离市场价,直接质疑你的专业性。
- 缓存导致币种串台。 选了欧元却显示美元价格,必须按币种做缓存变体。
- 结算币种与展示币种不一致。 页面显示欧元,扣款按美元,是典型的信任事故。
- 案例: 某外贸站手动填了汇率两年未更新,美元对欧元汇率变动超过 10%,欧洲客户按页面价格做预算,实际签约时价格高出一大截,导致两笔订单直接谈崩。改成了每日自动更新加明确标注更新时间。
- 接口失败时显示错误价格。
wp_remote_get失败后不能回落到默认值 1,应保留上一次成功的值。 - B2B 站做了实时结算。 反而增加了客户 confusion,报价展示就够了。
- 忽略了货币符号与格式。 欧元符号在部分欧洲国家放在数字后面,需要用
woocommerce_currency_symbol过滤器调整。
总结
多币种的策略先分场景:B2B 只做”基准报价 + 参考换算 + 更新时间标注”,B2C 才做实时结算并用成熟插件。技术上用 option 存汇率、每日定时更新、woocommerce_currency 与 woocommerce_product_get_price 两个过滤器切换,缓存层必须按币种区分变体。判断标准:客户在任何币种下看到的价格,都能追溯到明确的汇率与更新时间。产品页的价格展示方式见外贸产品页结构设计;面向欧盟客户的合规要求见外贸站合规页面清单。
