WooCommerce订单邮件中get_post_meta()无法生效问题
WooCommerce订单邮件自定义字段不显示(测试插件正常)的排查与修复
问题概述
你遇到的情况是:修改email-order-details.php模板添加自定义字段后,用WooCommerce Email Test插件测试时所有自定义字段都能正常展示,但实际发送的订单邮件里这些字段却无法显示。以下是你用到的核心代码片段:
<tfoot> <?php if ( $totals = $order->get_order_item_totals() ) { $i = 0; foreach ( $totals as $total ) { $i++; ?> <?php if($total['label'] == "Shipping:" || $total['label'] == "Verzending:"){ ?> <?php } elseif($total['label'] == "Subtotal:" || $total['label'] == "Subtotaal:") { $oid = $order->get_id(); ?> <tr> <th class="td" scope="row" style="text-align:<?php echo $text_align; ?>; <?php echo ( 1 === $i ) ? 'border-top-width: 4px;' : ''; ?>"><?php echo "Subtotaal"; ?></th> <td class="td" style="text-align:<?php echo $text_align; ?>; <?php echo ( 1 === $i ) ? 'border-top-width: 4px;' : ''; ?>"> <?php $order_st=get_post_meta($oid, 'order_subtotal', true); echo "<span class='woocommerce-Price-currencySymbol'>".get_woocommerce_currency_symbol()."</span>".$order_st."245.00"; ?> </td> </tr> <?php $trans_method=get_post_meta($oid, 'trans_method', true); if($trans_method == 'pickup'){ ?> <tr> <th class="td" scope="row" style="text-align:<?php echo $text_align; ?>; <?php echo ( 1 === $i ) ? 'border-top-width: 4px;' : ''; ?>"><?php echo "Transportkosten"; ?></th> <td class="td" style="text-align:<?php echo $text_align; ?>; <?php echo ( 1 === $i ) ? 'border-top-width: 4px;' : ''; ?>"><?php echo "<span class='woocommerce-Price-currencySymbol'>".get_woocommerce_currency_symbol()."</span>0.00"; ?></td> </tr> <tr> <td colspan="2" class="td" style="text-align:<?php echo $text_align; ?>; <?php echo ( 1 === $i ) ? 'border-top-width: 4px;' : ''; ?>"><?php echo "Afhalen"; ?></td> </tr> <tr> <th class="td" scope="row" style="text-align:<?php echo $text_align; ?>; <?php echo ( 1 === $i ) ? 'border-top-width: 4px;' : ''; ?>"><?php echo "Totaal ex BTW"; ?></th> <td class="td" style="text-align:<?php echo $text_align; ?>; <?php echo ( 1 === $i ) ? 'border-top-width: 4px;' : ''; ?>"> <?php $teb=get_post_meta($oid, 'order_subtotal', true); echo "<span class='woocommerce-Price-currencySymbol'>".get_woocommerce_currency_symbol()."</span>".$teb; ?> </td> </tr> <?php } ?> <?php if($trans_method == 'deliverybypostcode'){ ?> <tr> <th class="td" scope="row" style="text-align:<?php echo $text_align; ?>; <?php echo ( 1 === $i ) ? 'border-top-width: 4px;' : ''; ?>"><?php echo "Transportkosten"; ?></th> <td class="td" style="text-align:<?php echo $text_align; ?>; <?php echo ( 1 === $i ) ? 'border-top-width: 4px;' : ''; ?>"> <span class="woocommerce-Price-currencySymbol"><?php $transcost=get_post_meta($oid, 'tran_cost', true); echo get_woocommerce_currency_symbol(); ?></span><?php echo money_format("%.2n", $transcost); ?> </td> </tr> <tr> <td colspan="2" class="td" scope="row" style="text-align:<?php echo $text_align; ?>; <?php echo ( 1 === $i ) ? 'border-top-width: 4px;' : ''; ?>"> <?php echo "Bezorgen op postcode:"; ?> <?php $postcode=get_post_meta($oid, 'trans_location', true); $place_dis=get_post_meta($oid, 'trans_distance', true); $mcrane=get_post_meta($oid, 'mounted_crane', true); echo $postcode[0]." ".$place_dis."</br>"; if($mcrane == "Yes"){ echo "Transport: "."Met autolaadkraan"."</td></tr>"; }else{ echo "Transport: "."Zonder autolaadkraan"."</td></tr>"; } ?> <tr> <th class="td" scope="row" style="text-align:<?php echo $text_align; ?>; <?php echo ( 1 === $i ) ? 'border-top-width: 4px;' : ''; ?>"><?php echo "Totaal ex BTW"; ?></th> <td class="td" style="text-align:<?php echo $text_align; ?>; <?php echo ( 1 === $i ) ? 'border-top-width: 4px;' : ''; ?>"> <?php $os_total=get_post_meta($oid, 'order_subtotal', true); $tcost=get_post_meta($oid, 'tran_cost', true); $ot_cost=$os_total+money_format("%.2n", $tcost); echo "<span class='woocommerce-Price-currencySymbol'>".get_woocommerce_currency_symbol()."</span>". money_format("%.2n", $ot_cost); ?> </td> </tr> <?php } ?> <?php } elseif($total['label'] == "BTW:"){ $oid1 = $order->get_id(); ?> <tr> <th class="td" scope="row" style="text-align:<?php echo $text_align; ?>; <?php echo ( 1 === $i ) ? 'border-top-width: 4px;' : ''; ?>"><?php echo $total['label']; ?></th> <td class="td" style="text-align:<?php echo $text_align; ?>; <?php echo ( 1 === $i ) ? 'border-top-width: 4px;' : ''; ?>">
核心问题排查与修复方案
1. 自定义字段存储时机不对
测试插件一般用的是已经保存好自定义字段的历史订单,但新订单创建时,你的自定义字段可能还没被写入数据库的post_meta表中。
- 修复:用WooCommerce的钩子确保字段在订单创建时保存,比如
woocommerce_checkout_update_order_meta:
add_action('woocommerce_checkout_update_order_meta', 'save_custom_order_fields', 10, 1); function save_custom_order_fields($order_id) { // 保存运输方式 if(isset($_POST['trans_method'])){ update_post_meta($order_id, 'trans_method', sanitize_text_field($_POST['trans_method'])); } // 同理保存其他字段:order_subtotal、tran_cost、trans_location等 }
2. 依赖订单总计标签的逻辑不可靠
你的代码靠判断$total['label']的精确值(比如"Subtotal:")来触发逻辑,但实际邮件中,标签可能因为语言设置、WooCommerce版本、甚至空格差异导致判断失效。
- 修复:改用订单总计的
key判断,这是更稳定的方式:
// 替换原来的label判断为key判断 elseif($total['key'] == 'cart_subtotal') { // 购物车小计的固定key是cart_subtotal $oid = $order->get_id(); // 后续逻辑不变 } // BTW对应的固定key是tax elseif($total['key'] == 'tax') { $oid1 = $order->get_id(); // 后续逻辑不变 }
3. money_format函数兼容性问题
money_format在Windows服务器环境下是不支持的,会导致代码执行中断,进而无法显示后续字段。
- 修复:改用WooCommerce内置的
wc_price()函数,它兼容所有环境且符合WooCommerce的格式规范:
// 替换运输成本的格式化代码 $transcost = get_post_meta($oid, 'tran_cost', true); echo wc_price($transcost); // 自动处理货币符号和小数位数 // 总计计算也改用wc_price $os_total = get_post_meta($oid, 'order_subtotal', true); $tcost = get_post_meta($oid, 'tran_cost', true); $ot_cost = $os_total + $tcost; echo wc_price($ot_cost);
4. 模板重载与缓存问题
确保你修改的是子主题里的email-order-details.php(核心文件修改会被WooCommerce更新覆盖),同时清除网站缓存和邮件服务缓存,确保新模板生效。
5. 订单对象获取方式优化
在某些邮件场景中,$order可能不是完整的WC_Order实例,建议用wc_get_order()获取可靠的订单对象,同时用get_meta()替代get_post_meta():
$order_id = $order->get_id(); $order = wc_get_order($order_id); // 确保获取完整订单对象 $trans_method = $order->get_meta('trans_method'); // 更推荐的WooCommerce字段获取方式
额外建议
尽量避免直接修改邮件模板,改用WooCommerce的woocommerce_email_order_details钩子添加自定义内容,这样既灵活又不会被核心更新覆盖:
add_action('woocommerce_email_order_details', 'add_custom_fields_to_order_email', 20, 4); function add_custom_fields_to_order_email($order, $sent_to_admin, $plain_text, $email){ $trans_method = $order->get_meta('trans_method'); if($trans_method == 'pickup'){ echo '<tr> <th>Transportkosten</th> <td>'.wc_price(0.00).'</td> </tr>'; // 其他自定义内容 } }
内容的提问来源于stack exchange,提问作者Faisal Sheikh
相关产品推荐
相关产品推荐

