
本文介绍如何通过 WooCommerce 标准钩子(如 woocommerce_thankyou 和 woocommerce_payment_complete)准确判断订单是否已支付,并基于支付状态执行重定向、写入用户元数据或触发后续逻辑,避免使用不存在的函数(如 get_wpmg_woocommerce_payment_tokens)。
本文介绍如何通过 woocommerce 标准钩子(如 `woocommerce_thankyou` 和 `woocommerce_payment_complete`)准确判断订单是否已支付,并基于支付状态执行重定向、写入用户元数据或触发后续逻辑,避免使用不存在的函数(如 `get_wpmg_woocommerce_payment_tokens`)。
WooCommerce 并不通过“支付 token”字段直接暴露用户是否完成付款——尤其对非订阅类一次性订单,关键依据应是订单本身的支付时间(date_paid),而非孤立的 token 存在与否。你原代码中尝试调用的 get_wpmg_woocommerce_payment_tokens 并非 WooCommerce 官方函数,也未被核心或主流支付网关定义,属于无效调用,需立即替换为标准、可靠的方式。
✅ 推荐方案:使用官方支付完成钩子
最健壮且语义明确的做法,是在订单真正支付成功后触发逻辑。WooCommerce 提供两个关键动作钩子:
- woocommerce_thankyou:用户访问订单完成页(/checkout/order-received/)时触发,但不保证支付已到账(例如货到付款订单也会触发);
- woocommerce_payment_complete:仅当订单状态变为“processing”或“completed”且 date_paid 被设置时触发,是判断“支付已完成”的黄金标准。
以下是生产环境推荐的实现方式:
// ✅ 在 functions.php 或专用插件中添加
add_action('woocommerce_payment_complete', 'handle_payment_success_and_update_user');
function handle_payment_success_and_update_user($order_id) {
$order = wc_get_order($order_id);
if (!$order || !$order->get_date_paid()) {
return; // 安全兜底:确保支付时间存在
}
$user_id = $order->get_customer_id();
if ($user_id <blockquote><p>⚠️ 注意:woocommerce_payment_complete 运行于后台(无 HTTP 响应上下文),<strong>不能直接调用 header() 或 exit</strong>。若你当前需求是“用户访问某课程页面时,检查其是否已付费,未付费则跳转至结算页”,请改用前端校验逻辑:</p></blockquote><pre class="brush:php;toolbar:false;">// 示例:在课程页面模板中安全检查并跳转(放在模板顶部,早于任何 HTML 输出)
if (is_singular('sfwd-lessons') || get_post_type() === 'sfwd-lessons') {
$lesson_id = get_the_ID();
$user_id = get_current_user_id();
if ($user_id > 0) {
// 查询该用户是否有已支付的关联订单(可根据产品 ID / 课程 ID 关联)
$paid_order_ids = wc_get_orders([
'status' => ['wc-completed', 'wc-processing'],
'customer' => $user_id,
'limit' => 1,
'return' => 'ids',
'meta_query' => [
[
'key' => '_billing_email', // 或更精准地关联课程(需自定义订单元字段)
'compare' => 'EXISTS'
]
]
]);
if (empty($paid_order_ids)) {
wp_redirect('https://xx/checkouts/checkout-page/');
exit;
}
}
}? 补充说明:关于“Payment Token”
WooCommerce 的支付 token(如信用卡 token)主要用于重复扣款场景(如订阅),由支付网关(如 Stripe、PayPal)生成并存储在 wp_woocommerce_payment_tokens 表中。普通订单无需也不应依赖 token 判断支付结果。若你确需查询 token,应使用:
$tokens = WC_Payment_Tokens::get_customer_tokens($user_id, 'stripe'); // 指定网关 ID
但再次强调:token 存在 ≠ 订单已支付。它仅代表用户曾保存过某种支付方式。
✅ 总结建议
- ✅ 优先使用 woocommerce_payment_complete 处理支付成功后的数据写入、通知、同步等后台任务;
- ✅ 前端访问控制(如课程页跳转)应在 PHP 模板中结合 wc_get_orders() 主动查询用户历史订单状态;
- ❌ 避免虚构函数、依赖未定义的 meta 字段或误读 token 含义;
- ? 所有重定向必须在输出前执行(wp_redirect() + exit),且不可在 AJAX 或钩子回调中直接使用 header()。
通过以上方式,你将获得稳定、可维护、符合 WooCommerce 最佳实践的支付状态处理逻辑。










