互客鱼 返回主站

WordPress 和 WooCommerce

页面构建器

很大一部分现实世界的 WordPress 站点使用页面构建器而不是普通的 Gutenberg。 hukeyu 插件在将 HTML 发送到您的互客鱼智能体之前, 使用每个支持的构建器的原生 API 渲染其页面,因此同步的内容 是访客实际看到的内容。

本页解释了检测 + 渲染的工作原理、支持哪些构建器, 以及如何使用过滤器覆盖行为。

为什么这很重要

大多数页面构建器不将渲染的页面存储在 post_content 中。 它们将布局树保存在 postmeta 中,并在渲染时重新组合 HTML。 如果您的同步管道天真地读取 post_content 并调用 apply_filters('the_content', …),您会得到:

  • Elementor:空字符串。布局完全存在于 _elementor_data postmeta 中。
  • Bricks:空。布局在 _bricks_page_content_2 中。
  • Oxygen:单个 [oxygen_html] 短代码存根。真正的布局在 ct_builder_shortcodes postmeta 中。
  • Beaver Builder:如果构建器从未有机会覆盖,则是简化的 "fallback" HTML。
  • Divipost_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 站点地图生成器、架构标记插件等)。