
本文介绍如何通过全局变量桥接机制,在 woocommerce_order_item_meta_start 钩子中准确识别并仅在特定邮件(如 customer_completed_order)中显示自定义产品元字段,解决 $email 对象不可用的问题。
本文介绍如何通过全局变量桥接机制,在 `woocommerce_order_item_meta_start` 钩子中准确识别并仅在特定邮件(如 `customer_completed_order`)中显示自定义产品元字段,解决 `$email` 对象不可用的问题。
在 WooCommerce 中,woocommerce_order_item_meta_start 钩子本身不传递 $email 对象,因此无法直接通过 $email->id 判断当前渲染的是哪封邮件(如“订单完成”或“新订单”)。若强行引用未定义的 $email 变量,会导致 PHP Notice 错误并使钩子失效——这正是你代码中断的根本原因。
要实现“仅在付款完成后(即 customer_completed_order 邮件)显示条款信息”,需采用跨钩子状态传递策略:利用 WooCommerce 邮件发送流程中更早触发、且明确提供 $email 对象的钩子(如 woocommerce_email_before_order_table),将邮件 ID 临时存入全局变量;再在目标钩子中读取该值进行条件判断。
以下是完整、健壮的实现方案:
✅ 步骤一:在邮件渲染前捕获并存储邮件 ID
// 在邮件表格渲染前,将当前邮件 ID 存入全局变量
add_action( 'woocommerce_email_before_order_table', 'set_current_email_id', 10, 4 );
function set_current_email_id( $order, $sent_to_admin, $plain_text, $email ) {
$GLOBALS['wc_current_email_id'] = $email->id;
}
此钩子在所有标准 WooCommerce 邮件模板中均会触发(包括客户邮件与管理员邮件),且 $email 对象完整可用,是安全可靠的“入口点”。
✅ 步骤二:在订单项元区域中读取并条件渲染
add_action( 'woocommerce_order_item_meta_start', 'display_terms_only_in_completed_email', 10, 4 );
function display_terms_only_in_completed_email( $item_id, $item, $order, $plain_text ) {
// 仅在邮件环境(非前端页面)且为普通商品行项目时执行
if ( is_wc_endpoint_url() || ! $item->is_type( 'line_item' ) ) {
return;
}
// 安全读取全局邮件 ID
$email_id = $GLOBALS['wc_current_email_id'] ?? '';
// 精确匹配目标邮件类型(支持多邮件扩展)
$target_emails = array( 'customer_completed_order', 'customer_processing_order' );
if ( empty( $email_id ) || ! in_array( $email_id, $target_emails, true ) ) {
return;
}
// 获取产品级自定义字段(注意:此处读取的是产品设置的 meta,非订单项 meta)
$ot_address = get_post_meta( $item->get_product_id(), 'ot_address', true );
// 若字段存在且非空,则渲染 HTML
if ( ! empty( $ot_address ) ) {
printf(
'<div class="order-item-terms">
<strong>%s:</strong> %s</div>',
esc_html__( 'Terms', 'woocommerce' ),
wp_kses_post( $ot_address )
);
}
}
⚠️ 关键注意事项
- 安全性强化:使用 esc_html__() 和 wp_kses_post() 分别处理翻译字符串与用户输入内容,防止 XSS;
- 兼容性保障:钩子参数数量已按 WooCommerce 8.0+ 标准设为 4($item_id, $item, $order, $plain_text),避免旧版兼容问题;
- 字段来源辨析:示例中读取的是产品层面的 ot_address(get_post_meta),若实际需显示订单项专属的自定义值(如用户下单时填写的条款版本),应改用 $item->get_meta('ot_address');
- 全局变量清理(可选):如需更高健壮性,可在 woocommerce_email_footer 钩子中 unset($GLOBALS['wc_current_email_id']),避免跨邮件污染。
该方案无需修改核心模板或依赖第三方插件,完全遵循 WooCommerce 钩子生命周期设计,稳定可靠,适用于所有标准邮件场景。











