前言:为什么会遇到“短代码嵌套”的痛点?

在使用 WordPress 构建电商站(特别是使用 WooCommerce + ACF + Avada 这套黄金组合)时,我们经常遇到一种非常复杂的需求链路:

  1. 后台数据录入:我们使用 ACF 创建了一个字段组,里面包含一个 WYSIWYG Editor(富文本编辑器)字段,名为“产品系列型号表格”(lier_product_serial_model_table)。
  2. 内容嵌套:在这个富文本字段里,我们并没有手动画表格,而是直接插入了 TablePress 插件生成的短代码,例如 [table id=1 /]。
  3. 前端调用:在产品详情页(使用 Avada 构建),我们写了一个自定义短代码(比如 [lier_acf_wysiwyg name="lier_product_serial_model_table"])来获取这个 ACF 字段的数据。

问题来了:当你刷新前台页面时,你看到的不是渲染好的漂亮表格,而是原封不动的 [table id=1 /] 这行文本!

这是因为 WordPress 默认在解析短代码时,只解析第一层。当外层短代码把 [table id=1 /] 当成纯文本输出到页面时,WordPress 已经错过了再次解析它的时机。

核心原理解析:do_shortcode() 的魔法

要解决这个问题,我们需要用到 WordPress 提供的一个核心函数:do_shortcode()。

它的作用非常简单粗暴:扫描一段字符串,找出里面所有的短代码,并强制执行它们。

在我们的需求链路中,实现逻辑如下:

  1. 用 get_field() 把 ACF 富文本字段里的内容(纯字符串)拿出来。
  2. 用 do_shortcode() 包裹这个字符串,TablePress 的短代码就会在这一刻被 WordPress 识别,并转化为真实的 HTML 表格。
  3. 输出最终解析好的 HTML 给前端。

实战实现:编写专用短代码

我们不再依赖任何现成的插件,直接手写一个高封装、只针对这种场景的专属短代码。

请将以下代码添加到你的子主题 functions.php 中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?php
/**
* ========================================================================
* Lier ACF 独立短代码 - 输出并解析 WYSIWYG 字段 (支持内部短代码嵌套)
* ========================================================================
*
* 【用法示例】:
* 在 Avada Code Block 或 文本区块 中直接调用:
* [lier_acf_wysiwyg name="lier_product_serial_model_table"]
*
* ========================================================================
*/

if ( ! function_exists( 'lier_acf_wysiwyg_shortcode' ) ) {
function lier_acf_wysiwyg_shortcode( $atts ) {
// 1. 定义默认参数
$atts = shortcode_atts(
array(
'name' => '', // ACF 字段的 Name (你截图里的 lier_product_serial_model_table)
'post_id' => false, // 默认获取当前产品ID
),
$atts,
'lier_acf_wysiwyg'
);

// 如果没填 name,直接返回
if ( empty( $atts['name'] ) ) {
return '';
}

// 2. 获取当前文章/产品 ID
$post_id = $atts['post_id'] ? $atts['post_id'] : get_the_ID();

// 3. 获取 ACF WYSIWYG 字段的内容
// 注意:这里一定要用 get_field 而不是 the_field,因为我们要处理它的返回值
$content = get_field( $atts['name'], $post_id );

// 4. 如果内容为空,直接返回
if ( empty( $content ) ) {
return '';
}

// 5. 【核心魔法】:使用 do_shortcode() 强制解析内容中的短代码
// 比如你的内容里写了 [table id=1 /],这一步就会把它变成真实的表格 HTML
$parsed_content = do_shortcode( $content );

// 6. 组装外层 HTML(方便你加 CSS 样式控制)
$output = '<div class="lier-acf-wysiwyg-wrapper">';
// 如果文本编辑器里加了换行,wpautop 可以自动补充 <p> 标签,保持排版
$output .= wpautop( $parsed_content );
$output .= '</div>';

return $output;
}
}
// 注册这个专门解析 WYSIWYG 的短代码
add_shortcode( 'lier_acf_wysiwyg', 'lier_acf_wysiwyg_shortcode' );

完整需求链路的后台操作演示

为了让你完全看懂这个场景,我们来模拟一遍完整的数据流动过程。

场景 1:后台录入数据

  1. 打开你的 WordPress 后台,进入 ACF -> 字段组。
  2. 确保你的“产品系列型号表格”字段类型为 WYSIWYG Editor,字段名为 lier_product_serial_model_table。
  3. 进入具体的产品编辑页面,找到这个字段。
  4. 关键操作:在富文本编辑器里,一定要切换到 “文本 (Text)” 模式,然后填入 TablePress 的短代码:
    1
    [table id=1 /]
    注意:千万不要在“可视化”模式下直接粘贴,否则 WordPress 会自动给你转义,导致无法解析。

场景 2:前端详情页调用

  1. 进入 Avada Builder 编辑该产品详情页。
  2. 拖入一个 Code Block 元素(或者文本块)。
  3. 在里面输入我们刚刚自定义的短代码:
    1
    [lier_acf_wysiwyg name="lier_product_serial_model_table"]
  4. 保存并刷新页面。

场景 3:最终渲染效果

页面在加载时的执行顺序是这样的:

  • 遇到 [lier_acf_wysiwyg ...],触发我们写的 PHP 函数。
  • 函数用 get_field() 拿到文本 [table id=1 /]。
  • PHP 调用 do_shortcode('[table id=1 /]'),TablePress 插件被激活,输出 <table>...</table> 的 HTML 代码。
  • 最终页面渲染出来的是一个带有完整样式、可以正常显示型号和参数的表格,而不是一堆奇怪的英文方括号。

💡 开发者的最佳实践总结

  1. **万物皆可 do_shortcode**:如果你以后还有其他插件(如图片灯箱、视频播放器)生成的短代码,你想把它封装在 ACF 字段里,或者想通过 PHP 模板输出,都可以用 do_shortcode() 来包裹它。
  2. 避免无限嵌套:虽然 WordPress 允许短代码嵌套,但尽量不要嵌套超过两层,否则会极其消耗服务器性能,且极易出现页面错乱。
  3. 安全过滤:因为是直接输出 HTML,如果你允许非管理员(如投稿者)编辑这个 WYSIWYG 字段,请务必在后台 ACF 设置里给这个字段开启一定的权限限制,防止 XSS 攻击。

这个name可以使用自定义字段组的label名称吗?

不可以的。 在代码和短代码层面,永远只能使用字段的 Name(字段名),不能使用 Label(标签名)。

这是一个非常容易混淆的点,我来为你详细解释一下 ACF 中 Label 和 Name 的底层区别,以及为什么不能混用。

1. 为什么不能用 Label?

  • Label(标签):是给人看的。比如你截图里的 Product serial model table。它是用来在 WordPress 后台编辑页面显示提示文字的。它可以包含中文、空格、特殊符号,你甚至可以把同一个字段组里的两个字段都命名为一样的 Label。
  • Name(字段名):是给代码和数据库看的。比如 lier_product_serial_model_table。它必须是唯一的,且只能包含英文字母、数字和下划线。WordPress 实际在数据库里存储数据时,是用这个 Name 作为 Key(键名)的。

如果你在短代码里写了 name="Product serial model table",PHP 会去数据库里找一把叫做 Product serial model table 的钥匙,这当然找不到,所以页面就会空白。


2. 如果我想在前端看到 Label,怎么办?

如果你不仅想调用数据,还想把后台设置的 Label(标签)作为标题或者前缀一起输出到前端,这就需要特殊处理了。

但是,强烈建议不要用 Label 去获取数据。 如果你觉得手写 Name 太长、太难记,我有两种更实用的替代方案:

方案 A:为你的字段改一个简短的 Name(推荐)

去 ACF 后台,把字段的 Name 改短一点。比如,把 lier_product_serial_model_table 改成 serial_table。这样你在短代码里只需要写 [lier_acf_wysiwyg name="serial_table"] 就行了。
(注意:如果你已经录入了数据,修改 Name 可能会导致之前填的数据丢失,请谨慎操作。)

方案 B:在短代码内部通过 Name 获取 Label(高级玩法)

如果你未来的需求是:“通过传入 Name,既输出 Label 作为标题,又输出值”。你可以改造一下刚才的 PHP 短代码。

比如加上一个 show_label="yes" 的参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
if ( ! function_exists( 'lier_acf_wysiwyg_shortcode' ) ) {
function lier_acf_wysiwyg_shortcode( $atts ) {
$atts = shortcode_atts(
array(
'name' => '',
'post_id' => false,
'show_label' => 'no', // 新增:是否显示标签
),
$atts,
'lier_acf_wysiwyg'
);

if ( empty( $atts['name'] ) ) return '';

$post_id = $atts['post_id'] ? $atts['post_id'] : get_the_ID();

// 获取内容
$content = get_field( $atts['name'], $post_id );
if ( empty( $content ) ) return '';

$output = '<div class="lier-acf-wysiwyg-wrapper">';

// 如果要求显示标签
if ( $atts['show_label'] === 'yes' ) {
// 通过 Name 获取整个字段对象,从而提取出 Label
$field_object = get_field_object( $atts['name'], $post_id );
if ( $field_object && isset( $field_object['label'] ) ) {
$output .= '<h3 class="lier-wysiwyg-title">' . esc_html( $field_object['label'] ) . '</h3>';
}
}

// 解析嵌套短代码
$parsed_content = do_shortcode( $content );
$output .= wpautop( $parsed_content );
$output .= '</div>';

return $output;
}
}
add_shortcode( 'lier_acf_wysiwyg', 'lier_acf_wysiwyg_shortcode' );

此时在前端调用:

1
[lier_acf_wysiwyg name="lier_product_serial_model_table" show_label="yes"]

前端效果:

Product serial model table (这是自动抓取的 Label)
[这里是你渲染出来的 TablePress 表格]

总结

短代码里的 name="xxx" 永远填你截图里 Name 那一列的英文字符串(lier_product_serial_model_table)。不要填带空格的 Label。