
本文详解为何 do_shortcode() 在 functions.php 中直接 echo 失效,并提供安全、规范的解决方案——通过钩子返回值方式执行短代码,兼容 acf 自定义字段与 woocommerce 钩子机制。
在 WordPress 主题开发中,常需将 ACF(Advanced Custom Fields)字段中存储的含短代码内容(如 [my_banner] 或 [product_table])动态渲染到 WooCommerce 商品详情页。但许多开发者会遇到 do_shortcode() 不生效的问题,典型表现是:页面空白、短代码原样输出,或 PHP 报错“Cannot use echo in function hooked to action”。
根本原因在于:
✅ woocommerce_after_single_product_summary 是一个 action 钩子(非 filter),它不接收/返回值,仅用于“执行操作”;
❌ the_field('product_tree') 是 ACF 的直接输出函数(等价于 echo get_field(...)),返回 void,不能赋值给变量;
❌ 在 action 回调中 echo do_shortcode($field) 虽语法合法,但若 $field 为空、含非法字符或短代码本身未注册,将静默失败或破坏 HTML 结构。
✅ 正确做法:使用 get_field() + 显式返回(注意:原答案存在逻辑错误,需修正)
⚠️ 原答案中将 custom_single_product_banner 函数签名改为接收 $result 参数并 return $result 是错误的——该钩子并未传递任何参数,WordPress 会忽略该参数,且不会捕获返回值。woocommerce_after_single_product_summary 是纯 action,不支持返回内容。
✅ 正确解法应为:在 action 回调中安全获取字段、执行短代码,并直接输出(echo)结果,但必须确保:
- 使用 get_field()(非 the_field())获取原始字符串;
- 检查字段值非空且为字符串;
- 对短代码结果做 wp_kses_post() 过滤(可选,提升安全性);
- 确保短代码已正确注册且上下文有效。
以下是修复后的标准写法:
add_action( 'woocommerce_after_single_product_summary', 'custom_single_product_banner', 12 );
function custom_single_product_banner() {
global $post;
if ( ! $post || ! is_singular( 'product' ) ) {
return;
}
// 安全获取 ACF 字段值(传入 $post->ID 显式指定上下文)
$shortcode_content = get_field( 'product_tree', $post->ID );
// 验证字段存在、非空、且为字符串
if ( ! empty( $shortcode_content ) && is_string( $shortcode_content ) ) {
// 执行短代码并输出(注意:do_shortcode 返回解析后的内容,需 echo)
echo do_shortcode( $shortcode_content );
}
}? 关键要点说明:
- get_field() vs the_field():前者返回字符串,后者直接输出并返回 null,不可用于 do_shortcode() 输入;
- 显式传入 $post->ID:避免在循环或非主查询中获取错误字段值;
- 上下文校验:is_singular('product') 确保仅在商品单页执行,防止后台或其他页面误触发;
- 安全过滤(推荐):若短代码输出含 HTML,建议包裹 echo wp_kses_post( do_shortcode( $shortcode_content ) ); 防止 XSS(尤其当字段内容由非管理员编辑时);
- 调试技巧:临时添加 error_log( print_r( $shortcode_content, true ) ); 查看字段原始值,确认是否为空或格式异常。
✅ 总结
do_shortcode() 本身完全可用,问题根源在于字段获取方式错误与钩子语义误解。牢记:Action 钩子用于“执行”,需 echo 输出;Filter 钩子用于“转换”,需 return。本例属于典型的 Action 场景,正确姿势是 get_field() + do_shortcode() + echo,辅以健壮性检查,即可稳定渲染 ACF 中的短代码内容。










