You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP8/8.1下Hyyan Polylang for WooCommerce变量商品报错求助

问题:PHP8+下Hyyan Polylang for WooCommerce插件可变商品崩溃问题

问题背景

长期使用Hyyan Polylang for WooCommerce插件,将主机PHP版本从7.4升级到8/8.1后,可变商品出现崩溃(无按钮、部分组件缺失),但简单商品正常。

报错信息

调试时触发致命错误:

Fatal error: Uncaught TypeError: NumberFormatter::format(): Argument #1 ($num) must be of type int|float, string given in /home/t80469/public_html/wp-content/plugins/woo-poly-integration/src/Hyyan/WPI/LocaleNumbers.php:97 Stack trace: #0 /home/t80469/public_html/wp-content/plugins/woo-poly-integration/src/Hyyan/WPI/LocaleNumbers.php(97): NumberFormatter->format('', 3) #1 /home/t80469/public_html/wp-includes/class-wp-hook.php(308): Hyyan\WPI\LocaleNumbers->getLocalizedDecimal('', '') #2 /home/t80469/public_html/wp-includes/plugin.php(205): WP_Hook->apply_filters('', Array) #3 /home/t80469/public_html/wp-content/plugins/woocommerce/includes/wc-formatting-functions.php(358): apply_filters('woocommerce_for...', '', '') #4 [internal function]: wc_format_localized_decimal('') #5 /home/t80469/public_html/wp-content/plugins/woocommerce/includes/wc-formatting-functions.php(1330): array_map('wc_format_local...', Array) #6 /home/t80469/public_html/wp-content/plugins/woocommerce/includes/class-wc-product-variable.php(370): wc_format_dimensions(Array) #7 /home/t80469/public_html/wp-content/plugins/woocommerce/includes/class-wc-product-variable.php(312): WC_Product_Variable->get_available_variation(Object(WC_Product_Variation)) #8 /home/t80469/public_html/wp-content/plugins/woocommerce/includes/wc-template-functions.php(1749): WC_Product_Variable->get_available_variations() #9 /home/t80469/public_html/wp-includes/class-wp-hook.php(308): woocommerce_variable_add_to_cart('') #10 /home/t80469/public_html/wp-includes/class-wp-hook.php(332): WP_Hook->apply_filters('', Array) #11 /home/t80469/public_html/wp-includes/plugin.php(517): WP_Hook->do_action(Array) #12 /home/t80469/public_html/wp-content/plugins/woocommerce/includes/wc-template-functions.php(1697): do_action('woocommerce_var...') #13 /home/t80469/public_html/wp-includes/class-wp-hook.php(308): woocommerce_template_single_add_to_cart('') #14 /home/t80469/public_html/wp-includes/class-wp-hook.php(332): WP_Hook->apply_filters(NULL, Array) #15 /home/t80469/public_html/wp-includes/plugin.php(517): WP_Hook->do_action(Array) #16 /home/t80469/public_html/wp-content/plugins/woocommerce/templates/content-single-product.php(60): do_action('woocommerce_sin...') #17 /home/t80469/public_html/wp-includes/template.php(785): require('/home/t80469/pu...') #18 /home/t80469/public_html/wp-content/plugins/woocommerce/includes/wc-core-functions.php(284): load_template('/home/t80469/pu...', false) #19 /home/t80469/public_html/wp-content/plugins/woocommerce/templates/single-product.php(37): wc_get_template_part('content', 'single-product') #20 /home/t80469/public_html/wp-includes/template-loader.php(106): include('/home/t80469/pu...') #21 /home/t80469/public_html/wp-blog-header.php(19): require_once('/home/t80469/pu...') #22 /home/t80469/public_html/index.php(17): require('/home/t80469/pu...') #23 {main} thrown in /home/t80469/public_html/wp-content/plugins/woo-poly-integration/src/Hyyan/WPI/LocaleNumbers.php on line 97

临时解决方法

找到插件目录下的/plugins/woo-poly-integration/src/Hyyan/WPI/LocaleNumbers.php文件,注释掉原本被作者注释后又启用的代码:

//add_filter('woocommerce_format_localized_decimal', array($this, 'getLocalizedDecimal'), 10, 2);

完整上下文:

/**
 * Hook relevant WooCommerce filters to apply localisation according to Polylang locale.
 */
public function __construct()
{
    if (
            class_exists('\NumberFormatter') &&
            'on' === Settings::getOption('localenumbers', Features::getID(), 'on')
    ) {

        //localise standard price formatting arguments
        add_filter('wc_get_price_decimal_separator', array($this, 'getLocaleDecimalSeparator'), 10, 1);
        add_filter('wc_get_price_thousand_separator', array($this, 'getLocaleThousandSeparator'), 10, 1);
       add_filter('wc_price_args', array($this, 'filterPriceArgs'), 10, 1);

        //WooCommerce 3.1 unreleased checkin https://github.com/woocommerce/woocommerce/pull/15628
        //add_filter('woocommerce_format_localized_decimal', array($this, 'getLocalizedDecimal'), 10, 2);
        //no additional override on finished price format as no currency paramber available
        //add_filter('woocommerce_format_localized_price', array($this, 'getLocalizedPrice'), 10, 2);
    }
}

注释后调试无报错,可变商品按钮恢复正常,但希望了解:

  1. getLocalizedDecimal函数的重要性
  2. PHP8+中NumberFormatter的变化
  3. 如何正确替代该函数

解答

1. getLocalizedDecimal函数的重要性

这个函数的作用是根据Polylang设置的当前语言区域,格式化十进制数值,比如把小数点分隔符、千位分隔符转换成对应语言的格式(比如法语用逗号做小数点,英语用点)。它挂钩woocommerce_format_localized_decimal过滤器,会在WooCommerce处理价格、尺寸、重量等带小数的数值时触发,确保数值显示符合当前语言的本地化规范。

不过从代码上下文看,作者原本就注释了这个钩子,说明它是针对WooCommerce某个未发布版本(3.1)的兼容代码,核心的本地化逻辑已经通过wc_get_price_decimal_separator、wc_get_price_thousand_separator和wc_price_args这几个钩子实现了,所以禁用它不会影响核心的价格本地化功能。

2. PHP8+中NumberFormatter的变化

PHP8.0开始,对类型检查变得严格:

  • PHP7.x中,NumberFormatter::format()方法接收字符串类型的数值时会自动隐性转换;
  • PHP8.0+中,该方法的第一个参数$num明确要求是int|float类型,传入字符串会直接抛出TypeError,这就是你升级后报错的根本原因——代码中传入了空字符串''给这个方法,PHP8+不再自动转换,直接触发致命错误。

3. 正确替代/修复方案

如果需要保留该函数的功能,不需要完全注释掉钩子,而是修改getLocalizedDecimal函数的实现,在调用NumberFormatter::format()前先做类型校验和转换:

打开LocaleNumbers.php找到getLocalizedDecimal方法(大概在97行附近),修改为:

public function getLocalizedDecimal($num, $locale = '')
{
    // 先处理空值或非数值情况
    if (empty($num) || !is_numeric($num)) {
        return $num;
    }

    // 转换为数值类型
    $num = is_string($num) ? floatval($num) : $num;

    $formatter = $this->getFormatter($locale);
    return $formatter->format($num, NumberFormatter::TYPE_DECIMAL);
}

这样修改后:

  • 遇到空字符串或非数值时直接返回原内容,避免触发类型错误;
  • 把字符串类型的数值转换为float后再传给format()方法,符合PHP8+的类型要求;
  • 同时保留了原有的本地化格式化功能。

另外,也可以检查商品的尺寸数据,确保可变商品的所有变体都正确填写了尺寸(报错栈显示是在处理wc_format_dimensions时触发,可能存在某个变体尺寸为空的情况),从数据源上避免空值传入。


内容的提问来源于stack exchange,提问作者libertarian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 09:59:53