PAYATHON 2026

WooCommerce 结账后未跳转到 payment gateway

支付小周

结论

从日志看,问题出在 payment gateway 插件的兼容性或支付流程实现,而不是 WordPress 核心。

调用栈显示,提示来自:

WC_DirectPayV3_Gateway->process_payment

网关代码直接读取了订单对象的 order_key 属性。WooCommerce 3.0 之后不再推荐直接访问订单属性,应使用订单对象提供的 getter:

$order->get_order_key()

不过,这条日志的 PHP 级别是 NOTICE,通常不会单独造成结账中断或跳转失败。更需要检查的是网关插件的 process_payment(),包括它是否正确生成了支付地址,以及是否向 WooCommerce 返回了正确的跳转结果。

排查和修复应先由 payment gateway 插件开发者或集成方处理。

日志具体说明了什么

关键内容是:

order_key was called incorrectly. Order properties should not be accessed directly.

这通常表示插件中使用了类似写法:

$order_key = $order->order_key;

WooCommerce 已通过 CRUD API 封装订单数据,正确写法是:

$order_key = $order->get_order_key();

调用栈还表明,这段代码是在结账付款阶段执行的:

WC_Checkout->process_order_payment
WC_DirectPayV3_Gateway->process_payment
WC_Abstract_Legacy_Order->__get

整个过程可以还原为:

  1. WordPress 正常接收结账请求。
  2. WooCommerce 进入订单付款处理。
  3. WooCommerce 调用 WC_DirectPayV3_Gateway 的 process_payment()。
  4. 网关插件读取订单数据时使用了旧接口。

日志中的请求:

POST /?wc-ajax=checkout HTTP/1.1

返回 HTTP 200,说明请求没有因 PHP 致命错误而直接失败。Nginx 把 PHP 输出到 stderr 并记为 error,也不代表请求遇到了致命异常。这里真正的 PHP 日志级别仍是 NOTICE。

为什么会直接进入 Thank You 页面

对于需要跳转到第三方网站的托管式支付网关,process_payment() 通常应返回:

return [
    'result'   => 'success',
    'redirect' => $gateway_url,
];

WooCommerce 收到这个结果后,前端结账脚本才会跳转到 $gateway_url。

如果插件错误地返回订单完成页,例如:

return [
    'result'   => 'success',
    'redirect' => $this->get_return_url($order),
];

用户就会直接看到 Thank You 页面,而不会进入支付网关。

其他可能的情况包括:

  • 插件未能取得网关支付 URL,随后回退到订单完成页。
  • process_payment() 过早调用了 $order->payment_complete()。
  • 插件将订单标记为 processing 或 completed 后,直接返回订单页面。
  • 网关 API 请求失败,但插件没有把失败结果返回给 WooCommerce。
  • 插件版本与当前 WooCommerce 或 PHP 版本不兼容。
  • 网关配置、商户凭据、测试或生产环境地址、回调地址发生了变化。
  • 结账 AJAX 响应被其他插件、主题代码或缓存机制修改。

仅凭这条 NOTICE,还不能认定它是跳转失败的唯一原因。不过,它已经证明网关插件仍在调用旧式 WooCommerce API,需要更新。

网关插件应如何修复

先把所有直接访问订单属性的代码改为对应的 getter。常见示例如下:

// 旧写法
$order_key = $order->order_key;
$order_id  = $order->id;
$total     = $order->order_total;
$email     = $order->billing_email;

// 推荐写法
$order_key = $order->get_order_key();
$order_id  = $order->get_id();
$total     = $order->get_total();
$email     = $order->get_billing_email();

接着检查 process_payment() 是否正确处理网关响应。简化示例:

public function process_payment($order_id)
{
    $order = wc_get_order($order_id);

    if (!$order) {
        wc_add_notice(__('Unable to create the payment.', 'your-text-domain'), 'error');

        return [
            'result' => 'failure',
        ];
    }

    $gateway_url = $this->create_gateway_payment($order);

    if (is_wp_error($gateway_url) || empty($gateway_url)) {
        $message = is_wp_error($gateway_url)
            ? $gateway_url->get_error_message()
            : __('The payment gateway did not return a redirect URL.', 'your-text-domain');

        wc_add_notice($message, 'error');

        return [
            'result' => 'failure',
        ];
    }

    $order->update_status(
        'pending',
        __('Waiting for payment at the external gateway.', 'your-text-domain')
    );

    return [
        'result'   => 'success',
        'redirect' => esc_url_raw($gateway_url),
    ];
}

只有在网关确认付款成功后,插件才应在回调或返回处理逻辑中执行:

$order->payment_complete($transaction_id);

用户刚点击“下单”但尚未完成支付时,不应调用该方法。

建议的排查步骤

1. 查看结账 AJAX 的实际响应

在浏览器开发者工具的 Network 面板中找到:

?wc-ajax=checkout

检查响应 JSON,重点查看:

{
  "result": "success",
  "redirect": "..."
}

如果 redirect 已经指向 WooCommerce 的 order-received 地址,基本可以确定问题出在网关插件的 process_payment() 返回逻辑。

如果响应中包含第三方支付地址,但浏览器没有跳转,再检查前端 JavaScript 错误、结账模板覆盖和优化插件。

2. 记录网关 API 的响应

在不记录银行卡号、CVV、密钥等敏感信息的前提下,应记录:

  • 请求是否真正发送到了支付网关。
  • 网关返回的 HTTP 状态码。
  • 响应中是否包含支付会话 ID。
  • 响应中是否包含跳转 URL。
  • 插件最终返回给 WooCommerce 的 result 和 redirect。

可以使用 WooCommerce 日志接口:

$logger = wc_get_logger();

$logger->debug(
    'Gateway payment session created.',
    [
        'source'   => 'directpay-v3',
        'order_id' => $order->get_id(),
    ]
);

不要把 API secret、完整支付令牌或银行卡数据写入日志。

3. 检查版本兼容性

确认近期是否更新过以下组件:

  • WooCommerce
  • WordPress
  • PHP
  • payment gateway 插件
  • 结账相关插件或当前主题

如果网关插件长期无人维护,应联系插件提供方,索取兼容当前 WooCommerce 版本的更新。直接修改第三方插件只适合临时验证,因为插件升级后,这些改动会被覆盖。

4. 在测试环境排除冲突

先备份网站,然后在 staging 环境中进行以下测试:

  • 切换到 WooCommerce 官方默认主题。
  • 暂停缓存、压缩和结账优化插件。
  • 暂停 WooCommerce 与该支付网关之外的其他插件。
  • 使用网关 sandbox 或测试商户账号重新下单。

如果问题仍然存在,可以把排查范围集中到网关插件及其远程 API。如果问题消失,再逐个恢复插件和主题,定位具体冲突。

应由哪一方处理

可以按以下方式划分责任:

  • 网关插件开发者或集成方:修复对 $order->order_key 的直接访问,并检查 process_payment() 返回值、支付 URL 生成逻辑和网关 API 错误处理。
  • 支付服务商:确认商户状态、API 凭据、接口地址、支付会话创建结果和服务端限制。
  • 网站维护方:提供版本信息、WooCommerce 状态报告、结账 AJAX 响应和脱敏后的网关日志,并完成冲突测试。
  • WooCommerce 或 WordPress 核心:现有日志没有显示问题来自核心代码。

最有效的处理方式,是把完整调用栈、结账 AJAX 响应、WooCommerce 状态报告和脱敏后的网关请求结果交给 payment gateway 插件开发者。当前日志已经明确表明,该插件至少有一处 WooCommerce 兼容性代码需要修复。

备注:内容仅供参考。