WordPress 和 WooCommerce
页面构建器
很大一部分现实世界的 WordPress 站点使用页面构建器而不是普通的 Gutenberg。 hukeyu 插件在将 HTML 发送到您的互客鱼智能体之前, 使用每个支持的构建器的原生 API 渲染其页面,因此同步的内容 是访客实际看到的内容。
本页解释了检测 + 渲染的工作原理、支持哪些构建器, 以及如何使用过滤器覆盖行为。
为什么这很重要
大多数页面构建器不将渲染的页面存储在 post_content 中。
它们将布局树保存在 postmeta 中,并在渲染时重新组合 HTML。
如果您的同步管道天真地读取 post_content 并调用
apply_filters('the_content', …),您会得到:
- Elementor:空字符串。布局完全存在于
_elementor_datapostmeta 中。 - Bricks:空。布局在
_bricks_page_content_2中。 - Oxygen:单个
[oxygen_html]短代码存根。真正的布局在ct_builder_shortcodespostmeta 中。 - Beaver Builder:如果构建器从未有机会覆盖,则是简化的 "fallback" HTML。
- Divi:
post_content中的短代码编码布局。只有当帖子循环正确初始化时才会正确渲染。
插件的 PageBuilderContent 助手显式处理每种情况。
第一个匹配获胜;不属于任何检测到的构建器的帖子回退到普通的
the_content 路径。
支持的构建器
| 构建器 | 检测 postmeta | 渲染器 |
|---|---|---|
| Elementor(Free + Pro) | _elementor_edit_mode = builder |
\Elementor\Plugin::$instance->frontend->get_builder_content_for_display($id, true) |
| Beaver Builder | _fl_builder_enabled = 1 |
FLBuilder::render_content_by_id($id) |
| Oxygen Builder | ct_builder_shortcodes(非空) |
do_shortcode($shortcodes) |
| Bricks Builder | _bricks_page_content_2(非空)且定义了 BRICKS_VERSION |
\Bricks\Frontend::render_content($payload) |
| Divi | _et_pb_use_builder = on |
通过 the_content 过滤器路由(已初始化 setup_postdata) |
每个渲染器都包裹在 try/catch (Throwable) 中。
抛出异常的构建器渲染器静默回退到下一个检测或普通路径,
因此更改其内部 API 的升级构建器版本永远不会使同步致命失败。
为什么 Divi 不同
Divi 确实 将其布局存储在 post_content 中 —
作为短代码编码标记,如
[et_pb_section][et_pb_row][et_pb_column][et_pb_text]…。
只有当帖子循环已初始化时,短代码才能通过 WordPress 过滤器链正确解析:
设置 $GLOBALS['post'] 并调用 setup_postdata()。
许多第三方插件(Yoast、Jetpack、嵌入处理程序)
也根据有效的 $post 全局变量限制其 the_content 回调。
如果没有 postdata 初始化,它们都会提前返回,同步的 HTML 会丢失
使页面真正有用的 chrome。
修复在插件 v2.0.0 中发布:
PostContentExtractor 始终初始化
$GLOBALS['post'] + 在过滤器链周围调用 setup_postdata(),
将工作包裹在 try/finally 中,并恢复 $GLOBALS['post']
+ 即使过滤器抛出异常也调用 wp_reset_postdata()。
线路看起来如何
对于标题为 "Pricing" 的 Elementor 页面,插件将完全渲染的 HTML
发送到 /api/v1/wp/posts/sync,就像浏览器接收它一样 —
包括节包装器、小部件 HTML 和 Elementor 自己的类名。
然后互客鱼在服务器端剥离标签进行分块,因此类名不会出现在嵌入中。
示例切片负载(截断以提高可读性):
{
"wp_id": 142,
"post_type": "page",
"permalink": "https://shop.example/pricing",
"title": "Pricing",
"content_html": "<div class=\"elementor elementor-142\"><section class=\"elementor-section …\">…</section>…</div>",
"excerpt": "Three plans, two outcomes…",
"content_hash": "ab12…ef90",
"modified_at": "2026-05-09T14:30:00+00:00",
"language": "en-us",
"taxonomy_terms": []
}
覆盖渲染的 HTML
hukeyu_post_content_html 过滤器在构建器渲染器运行后
(或在普通过滤器链运行后,对于非构建器帖子)接收最终 HTML —
因此您可以后处理它而无需关心哪个构建器拥有页面:
add_filter('hukeyu_post_content_html', function ($html, $post, $builder) {
// $builder 是以下之一:'elementor'、'beaver'、'oxygen'、'bricks'、
// 'divi',或对于普通 Gutenberg/Classic 帖子为 null。
if ($builder === 'elementor') {
// 剥离爬虫看不到的 Elementor 辅助 iframe。
$html = preg_replace('#<iframe[^>]*data-elementor-[^>]*>.*?</iframe>#is', '', $html);
}
return $html;
}, 10, 3);
返回空字符串会抑制该帖子的同步(互客鱼会接受空内容,
但智能体没有任何可检索的内容)。返回 null 会短路其余的过滤器链。
当构建器升级并中断时
页面构建器定期重命名其内部渲染器 — 当这种情况发生时, 插件的基于反射的调用回退到下一个路径,帖子就像普通 Gutenberg 帖子一样同步。 结果是降级(您可能会得到空字符串或短代码存根),但同步本身不会致命失败。
如果您注意到特定构建器版本产生空内容,请在 hukeyu repo 中提出问题,
并提供构建器名称 + 版本。修复通常是 PageBuilderContent
中渲染器调用的单行更新。
限制
- 动态数据小部件。 Elementor Pro 的 "Dynamic Tags" 拉取实时数据(购物车计数、用户名)在没有真实访客的情况下使用其默认回退渲染。
- 条件显示规则。 依赖于请求访客的可见性规则(仅登录用户、地理位置、A/B 变体)根据同步请求上下文解析,这是服务器端的。仅限于 "仅登录用户" 的部分不同步。
- 懒加载内联块。 纯 JavaScript 内容(作为 Elementor HTML 小部件嵌入的 React 微前端)永远不会在服务器端执行,因此同步的 HTML 反映的是占位符,而不是水合内容。
这些是服务器端渲染构建器布局的固有限制,适用于每个做同样事情的 CMS 插件 (Yoast SEO 站点地图生成器、架构标记插件等)。