
本文详解如何在用户访问 woocommerce 结账页面且购物车非空时,安全、可靠地发送一次个性化邮件通知,避免重复触发、未定义对象错误及钩子误用问题。
在 WooCommerce 开发中,为提升转化率或提供购物流程提示,常需在用户抵达结账页(/checkout/)时自动发送一封轻量级提醒邮件,例如:“您好,您的订单即将完成!”——但若实现不当,极易出现邮件重复发送、白屏报错(如 Call to a member function is_empty() on null)或根本无法触发等问题。核心原因通常在于:钩子选择错误、对象初始化缺失、条件判断松散。
✅ 正确钩子:仅作用于结账页上下文
原代码中使用的 woocommerce_after_shop_loop_item 钩子会在商品列表页(Shop 页面)每个商品下方执行多次,与结账流程完全无关。应替换为专属于结账页生命周期的钩子:
woocommerce_before_checkout_form —— 该钩子在结账表单渲染前触发,且仅在 /checkout/ 页面加载时执行一次,是理想切入点。
✅ 安全前提:校验对象可用性与业务逻辑
WooCommerce 的 WC()->cart 在某些场景(如 AJAX 请求、非前台页面、插件冲突)下可能尚未初始化。因此必须前置校验:
if ( ! WC()->cart ) {
return; // 防止 Fatal Error
}同时,需确保用户已登录、购物车非空、邮箱与姓名字段有效,形成完整防护链:
function send_checkout_greeting_email() {
// 1. 仅对已登录用户生效
if ( ! is_user_logged_in() ) {
return;
}
// 2. 确保 WooCommerce 购物车对象已就绪
if ( ! WC()->cart ) {
return;
}
// 3. 仅当购物车中有商品时触发
if ( WC()->cart->is_empty() ) {
return;
}
$current_user = wp_get_current_user();
$email = $current_user->user_email;
$name = $current_user->user_first_name; // 推荐使用 user_first_name(标准字段名)
// 4. 严格校验必要字段(防空值导致邮件失败)
if ( empty( $email ) || empty( $name ) ) {
return;
}
// 5. 构建邮件内容(推荐使用 WordPress i18n 函数支持多语言)
$subject = sprintf( __( 'Hello %s, your order is almost ready!', 'your-textdomain' ), esc_html( $name ) );
$body = sprintf(
__( 'Hi %s,<br><br>Your cart contains %d item(s). Proceed to checkout to complete your purchase!', 'your-textdomain' ),
esc_html( $name ),
WC()->cart->get_cart_contents_count()
);
$headers = array( 'Content-Type: text/html; charset=UTF-8' );
// 6. 发送邮件(注意:wp_mail() 是异步的,无需额外处理)
wp_mail( $email, $subject, $body, $headers );
}
add_action( 'woocommerce_before_checkout_form', 'send_checkout_greeting_email' );⚠️ 关键注意事项
- 禁止在循环钩子中调用:如 woocommerce_before_shop_loop_item、woocommerce_cart_actions 等,会导致邮件爆炸式发送;
- 勿依赖 is_checkout() 单独判断:该函数在部分主题或缓存环境下可能返回不准确结果,应以 woocommerce_before_checkout_form 钩子本身作为页面标识;
- 姓名字段兼容性:$current_user->user_firstname 并非 WordPress 标准字段(正确为 user_first_name),建议使用 get_user_meta( $current_user->ID, 'first_name', true ) 获取更健壮;
- 性能与用户体验:此操作发生在页面渲染前,耗时应控制在毫秒级;若需复杂逻辑(如查询订单历史),建议改用 AJAX 异步触发;
- 测试环境必做:启用 WordPress 调试模式(WP_DEBUG_LOG),检查是否出现 Undefined property 或 Trying to access array offset 类警告。
? 进阶方案:复用 WooCommerce 邮件模板样式
若需邮件外观与 WooCommerce 默认通知(如“新订单”)一致,可调用其内置邮件器:
// 替换原 wp_mail() 部分如下:
$mailer = WC()->mailer();
$message = $mailer->wrap_message(
sprintf( __( 'Hello %s', 'woocommerce' ), esc_html( $name ) ),
__( 'Your cart is ready for checkout!', 'woocommerce' )
);
$mailer->send( $email, $subject, $message, 'Content-Type: text/html\r\n' );该方式自动注入 WooCommerce 邮件头部、CSS 样式和响应式布局,大幅提升专业度与品牌一致性。
通过以上结构化实现,您将获得一个稳定、可维护、符合 WooCommerce 最佳实践的结账页邮件通知功能——每次用户打开 /checkout/ 页面且有商品时,精准、安静、友好地送达一条专属提示。










