本文介绍如何通过 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 被设置时触发
,是判断“支付已完成”的黄金标准。
以下是生产环境推荐的实现方式:
⚠️ 注意:woocommerce_payment_complete 运行于后台(无 HTTP 响应上下文),
不能直接调用 header() 或 exit
。若你当前需求是“用户访问某课程页面时,检查其是否已付费,未付费则跳转至结算页”,请改用前端校验逻辑:
? 补充说明:关于“Payment Token”
WooCommerce 的支付 token(如信用卡 token)主要用于
重复扣款场景(如订阅)
,由支付网关(如 Stripe、PayPal)生成并存储在 wp_woocommerce_payment_tokens 表中。普通订单无需也不应依赖 token 判断支付结果。若你确需查询 token,应使用:
但再次强调:
token 存在 ≠ 订单已支付
。它仅代表用户曾保存过某种支付方式。
✅ 总结建议
✅ 优先使用 woocommerce_payment_complete 处理支付成功后的数据写入、通知、同步等后台任务;
✅ 前端访问控制(如课程页跳转)应在 PHP 模板中结合 wc_get_orders() 主动查询用户历史订单状态;
❌ 避免虚构函数、依赖未定义的 meta 字段或误读 token 含义;
? 所有重定向必须在输出前执行(wp_redirect() + exit),且不可在 AJAX 或钩子回调中直接使用 header()。
通过以上方式,你将获得稳定、可维护、符合 WooCommerce 最佳实践的支付状态处理逻辑。
// ✅ 在 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 <= 0) {
return;
}
// ✅ 方案1:向用户元数据写入支付状态(可用于后续条件判断)
update_user_meta($user_id, 'last_payment_status', 'completed');
update_user_meta($user_id, 'last_payment_date', current_time('mysql'));
update_user_meta($user_id, 'last_order_id', $order_id);
// ✅ 方案2:根据业务需要,可在此处触发重定向逻辑(注意:此钩子无输出上下文,不可用 header())
// 若需前端跳转,请改用 JS 或配合 AJAX + 会话标记
}// 示例:在课程页面模板中安全检查并跳转(放在模板顶部,早于任何 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;
}
}
}$tokens = WC_Payment_Tokens::get_customer_tokens($user_id, 'stripe'); // 指定网关 ID