子比主题开发文档
使用指南Codestar Framework主题扩展在线部署AI 功能推荐插件赞助打赏

古腾堡块与正文模块

梳理子比主题古腾堡扩展入口、区块清单、短代码桥接、前台渲染依赖,以及新增正文块的推荐写法。

模块边界

子比主题的古腾堡能力不是独立页面系统,而是“编辑器 UI + 正文保存结构 + 主题前台渲染”的组合。开发时要先判断需求属于哪一层:

层级位置负责内容
后台注册inc/functions/admin/admin-main.php注册区块脚本、编辑器样式、区块分类和开关
编辑器逻辑js/gutenberg-extend.js / js/gutenberg-extend.min.js区块编辑面板、属性、保存结构、区块转换
多语言文案inc/functions/zib-js-i18n.php通过 zibll_block_var.i18n 提供编辑器中文文案
前台解析inc/functions/zib-theme.phpinc/functions/shop/shop.php、前台 JS短代码渲染、隐藏内容、代码高亮、视频、轮播、Tab、弹窗
样式资源css/editor-style.min.csscss/tinymce.css、主题前台 CSS编辑器预览和前台样式

如果只是给正文增加一个可复用展示模块,优先做古腾堡块或短代码桥接。如果模块需要写入订单、支付、用户资产、上传文件或修改业务状态,应把写入逻辑放在服务端 Ajax、Hook 或业务类里,古腾堡块只负责保存内容配置。

开关与资源注册

古腾堡入口由后台初始化注册:

if (function_exists('register_block_type') && !_pz('close_gutenberg')) {
    add_action('admin_init', 'zibll_block');
}

zibll_block() 注册三类资源:

资源文件用途
zibll_block scriptjs/gutenberg-extend.min.js编辑器区块逻辑
zibll_block stylecss/editor-style.min.css编辑器预览样式
font_awesome stylecss/font-awesome.min.css编辑器内 Font Awesome 图标

注册时使用:

register_block_type('zibll/block', array(
    'editor_script' => 'zibll_block',
    'editor_style'  => 'zibll_block',
));

编辑器文案通过 wp_localize_script() 注入:

wp_localize_script('zibll_block', 'zibll_block_var', array(
    'i18n' => zib_get_gutenberg_i18n_strings(),
));

扩展时要尊重主题开关:

开关影响
_pz('close_gutenberg')关闭主题古腾堡扩展时不要强行注册区块
_pz('disabled_autoembed', true)开启后主题会在编辑器里注销 core/embed
_pz('highlight_kg')highlight_zt影响代码高亮前台资源和主题

区块分类

主题会把区块放到自定义分类:

字段
slugzibll_block_cat
titleZibll主题模块

WordPress 5.8 及以上使用 block_categories_all,旧版本使用 block_categories。新增主题风格区块时应放入这个分类,避免散落在 WordPress 默认分类里。

registerBlockType('zibllblock/example', {
  title: 'Zibll:示例模块',
  category: 'zibll_block_cat',
})

区块清单

区块或格式slug保存结构主要用途
文件下载zibllblock/download静态 .file-download-box HTML正文附件下载、文件属性展示
Tab 栏目zibllblock/tabs / zibllblock/tabBootstrap Tab 结构多栏目正文内容
视频剧集zibllblock/dplayerfeatured.new-dplayer + .switch-video多集视频切换
超级嵌入zibllblock/iframeiframe 包裹结构嵌入外部视频、音乐或页面
剧集嵌入zibllblock/iframeseriesiframe + .switch-iframe多个嵌入地址切换
视频zibllblock/dplayer.new-dplayer.post-dplayer单视频播放
亮点zibllblock/feature.feature 静态 HTML图标、标题、简介
设定颜色zibllblock/set-colorRichText format <qc>行内文字颜色和背景色
弹窗zibllblock/modalBootstrap modal 结构正文内隐藏弹窗内容
折叠框zibllblock/collapse.panel + .collapse手风琴内容
高亮代码zibllblock/enlighter<pre><code data-enlighter-*></code></pre>代码高亮、行号、代码组
标题zibllblock/biaotih1h5.title-theme主题样式标题
隐藏内容zibllblock/hide-content[hidecontent]...[/hidecontent]评论、登录、密码、会员、付费可见
文章列表zibllblock/postslists[postslists ...]正文插入文章列表
文章/帖子zibllblock/postsbox[postsbox post_id="..."]正文插入单篇文章或帖子卡片
引言zibllblock/quote.quote_q 静态 HTML主题引言样式
提醒框zibllblock/alert.alert 静态 HTML可关闭提示框
按钮组zibllblock/buttons多个 .but 按钮正文按钮组合
幻灯片zibllblock/carousel.wp-block-carousel + .carousel图片轮播
无缝图zibllblock/seamlessimg.seamless-img + gallery商品详情长图等
商品zibllblock/productbox[productbox id="..."]正文插入商城商品卡片

静态块与短代码桥接

主题古腾堡块有两种保存方式。

静态 HTML 块会直接把前台需要的结构保存到正文,例如文件下载、Tab、视频、嵌入、弹窗、折叠、标题、引言、提醒框、按钮组、轮播和无缝图。它们依赖主题前台 CSS 和 JS 初始化,开发时要保持 class、data-* 和 Bootstrap 属性一致。

短代码桥接块只提供编辑器 UI,最终保存为主题短代码:

[postslists cat="1,2" topics="" orderby="date" style="text" count="12" paginate="ajax"]
[postsbox post_id="123"]
[productbox id="456"]
[hidecontent type="logged"]登录后可见内容[/hidecontent]

这类块的前台输出由 PHP 短代码回调决定。扩展时不要只改编辑器保存字符串,还要检查短代码回调是否支持对应参数、是否有权限判断、是否需要缓存清理。

文件下载块

zibllblock/download 支持两种文件来源:

来源保存字段说明
媒体库文件data-download-file通过附件 ID 下载,前台可继续走主题下载逻辑
外部地址href直接写入下载链接

保存结构保留这些关键节点:

<div class="muted-box file-download-box mb20">
  <div class="file-download-icon"></div>
  <div class="file-download-name">文件名</div>
  <a class="but c-blue file-download-btn" data-download-file="123">下载</a>
  <div class="file-download-desc">
    <div class="desc-left">ZIP文件</div>
    <div class="desc-right">1.2M</div>
  </div>
</div>

保存结构与普通附件下载

古腾堡的 zibllblock/download 和经典编辑器里的 zib_file 按钮最终都会生成 .file-download-box。媒体库文件会把附件 ID 写到 data-download-file,外部地址只写普通 href。这意味着主题只会托管站内附件的下载链路,外部地址仍然由目标站点自己处理。

经典编辑器按钮只在允许文件上传时显示。主题在 inc/functions/zib-theme.php 里通过 apply_filters('tinymce_upload_file', false) 判断是否加入 zib_file,论坛发帖编辑器会在当前用户具备 posts_upload_file 能力时挂上 __return_true

if (zib_bbs_current_user_can('posts_upload_file')) {
    add_filter('tinymce_upload_file', '__return_true');
}

后台论坛权限项对应 bbs_posts_upload_file,它控制“发帖允许在编辑器上传文件及插入附件下载模块”。扩展投稿或论坛编辑器时,不要只把按钮塞进 TinyMCE,还要先确认用户是否具备上传文件的业务权限。

前台 nonce 注入

保存到正文里的 data-download-file 不是最终下载地址。文章输出时,主题会在 the_content 过滤器里扫描下载按钮,并给每个附件 ID 注入一次性校验值:

function zib_the_content_download_link_replace($content)
{
    $pattern = '/<a(.*?)data-download-file="(.*?)"(.*?)>/';
    preg_match_all($pattern, $content, $matches);

    if ($matches) {
        foreach ($matches[2] as $val) {
            $nonce   = wp_create_nonce('download_file_' . $val);
            $content = str_replace(" data-download-file=\"$val\"", " download-nonce=\"$nonce\" data-download-file=\"$val\"", $content);
        }
    }

    return $content;
}
add_filter('the_content', 'zib_the_content_download_link_replace');

前端脚本点击 .file-download-btn 时会读取 data-download-filedownload-nonce,把按钮地址改成 admin-ajax.php?action=download_file&file={id}&nonce={nonce},并用新窗口打开。这里的 nonce 是防止正文里被随意拼接附件 ID,不是付费或会员权限判断。

下载 Ajax

普通附件下载由 action/media.php 注册:

add_action('wp_ajax_download_file', 'zib_ajax_download_file');
add_action('wp_ajax_nopriv_download_file', 'zib_ajax_download_file');

zib_ajax_download_file() 的核心流程是读取 file 参数、校验 wp_verify_nonce($_REQUEST['nonce'], 'download_file_' . $file_id)、确认附件存在、累加 download_amount,最后 header('location:' . $attachment_url) 跳转到真实附件地址。它适合公开附件的下载统计和基础防伪,不适合承载订单校验、会员权益、次数限制或隐藏资源。

如果只是想给普通附件追加提示,可以在正文层补充说明:

add_filter('the_content', 'zib_docs_download_box_notice', 20);

function zib_docs_download_box_notice($content)
{
    if (false === strpos($content, 'data-download-file=')) {
        return $content;
    }

    return $content . '<div class="muted-2-color px12 mt10">' . esc_html__('附件下载链接会定期刷新,请勿复制缓存后的下载地址。', 'zib_language') . '</div>';
}

普通 download_file Ajax 没有下载前 Hook。需要下载审计、风控、限速或订单上下文时,应扩展 Ajax 处理函数,或直接使用 Zibpay 下载链路提供的 Hook。

附件归属

主题保存文章或论坛帖子后,会扫描正文里的媒体标记,把附件挂到对应内容下:

preg_match_all('/(data-edit-file-id|data-download-file)="(\d+)"/', $post_content, $matches);

if (!empty($matches[2])) {
    zib_media_attach_action($matches[2], $post->ID);
}

这段逻辑挂在 new_edit_postsnew_add_postsbbs_edit_postsbbs_add_posts。因此扩展下载块时要保留 data-download-file="{attachment_id}",不要把附件 ID 改成只存在于自定义 JSON 或隐藏字段里,否则媒体归属、清理和后台统计都可能对不上。

与 Zibpay 付费下载的边界

付费资源、会员免费资源、订单下载、下载限速和下载日志都不要走 download_file。它们应该进入 Zibpay 付费下载与资源权限pay-download 路由,由主题在下载模板里再次校验文章 ID、资源序号、nonce、购买状态、免费次数和资源地址。

Zibpay 下载模板会提供下载前 Action 和文件本地化 Filter:

do_action('zibpay_download_before', $post_id, $down_id, $paid, $file_url, $file_local);
$file_local = apply_filters('zibpay_download_file_local', $file_local, $file_url, $post_id, $down_id, $paid);

判断边界可以按这张表执行:

场景推荐链路
正文公开附件zibllblock/downloadzib_file + download_file
外部公开下载地址下载块保存普通 href
需要登录后才能访问服务端先判断登录和内容权限,再输出下载块
付费资源、会员资源、免费次数Zibpay pay-download 路由
下载审计、限速、远程资源转本地Zibpay 下载 Hook 和 Filter

扩展附件下载时建议复用这个结构。若要增加权限、次数、积分或付费下载,服务端应接入已有下载权限和 Zibpay 流程,不要只在前端隐藏按钮。

视频与嵌入

视频相关块分四类:

场景前台关键结构
dplayer单个本地或流媒体视频.new-dplayer.post-dplayer
dplayerfeatured多集视频.new-dplayer + .switch-video
iframe单个外部嵌入.wp-block-embed iframe
iframeseries多个外部嵌入.iframe-series + .switch-iframe

视频块保存的数据包括 video-urlvideo-picdata-loopdata-autoplaydata-volumedata-scale-height 等。前台播放器初始化读取这些属性,因此新增视频相关能力时应新增属性而不是改已有属性含义。更完整的视频封面、DPlayer 初始化、剧集切换、iframe 嵌入和付费视频链路见 视频资源与播放器

嵌入块支持从 iframe 代码里提取 src,同时保存长宽比例。扩展时要对外部地址做白名单或输出转义,避免让编辑器内容变成不受控脚本入口。

高亮代码块

zibllblock/enlighter 是主题对 EnlighterJS 的编辑器封装。它不把代码块渲染成一套新的组件,而是保存为普通 pre > code.gl,再由前台脚本统一初始化高亮、行号、主题、代码组和工具栏。

后台常用功能里的代码高亮配置来自 inc/options/admin-options.php

配置默认值作用
highlight_kgtrue全局代码高亮开关;关闭后仍会处理主题明确标记的 code.glcode.special
highlight_hhfalse前台初始化 EnlighterJS 时是否显示行号
highlight_btntrue控制高亮工具栏是否显示;关闭后前台动态 CSS 会隐藏 .enlighter-toolbar
highlight_ztenlighter亮色模式默认高亮主题
highlight_dark_ztdracula深色模式默认高亮主题
highlight_maxheight400前台代码块最大高度,设置为 0 表示不限制

前台会在 zib_win_var() 输出 _win.highlight_* 配置。js/main.jsauto_fun() 初始化时按下面的规则选择代码块:

场景选择器
highlight_kg 开启pre code:not(.enlighter-origin)
highlight_kg 关闭pre code.gl:not(.enlighter-origin), pre code.special:not(.enlighter-origin)

因此,全局开关更像“是否自动接管所有普通代码块”。古腾堡高亮块和经典编辑器高亮块都会保存 class="gl",即使站点关闭普通代码块自动高亮,也能继续被主题识别。

初始化时主题会按需加载 js/enlighter/enlighterjs.min.css,并用 _win.highlight_zt 作为默认主题。明暗模式切换时,toggle-theme 会把 .enlighter-default 上的 enlighter-t-{亮色主题}enlighter-t-{暗色主题} 互相替换,所以扩展代码高亮时不要手动固定死高亮主题 class。

inc/functions/zib-head.php 还会输出两段动态 CSS:

if (_pz('highlight_kg') && _pz('highlight_maxheight')) {
    $styles .= '.enlighter-default .enlighter,.wp-block-zibllblock-enlighter:not(:has(.enlighter)),.enlighter-pre:not(:has(.enlighter)){max-height:' . _pz('highlight_maxheight') . 'px;overflow-y:auto !important;}';
}

if (_pz('highlight_kg') && !_pz('highlight_btn')) {
    $styles .= '.enlighter-toolbar{display:none !important;}';
}

这说明最大高度和工具栏显示不是编辑器独有能力,而是前台输出层统一控制。若要新增代码展示能力,应优先让保存结构进入这套选择器和动态 CSS,而不是另写一套滚动容器。

古腾堡块保存结构如下:

<pre>
  <code
    class="gl"
    data-enlighter-language="php"
    data-enlighter-theme=""
    data-enlighter-highlight="1,3-5"
    data-enlighter-linenumbers="true"
    data-enlighter-lineoffset="1"
    data-enlighter-title="示例"
    data-enlighter-group="demo"
  >...</code>
</pre>

这些属性在 inc/functions/zib-theme.php 中被加入文章内容允许属性,避免 WordPress 过滤掉高亮配置:

属性用途
data-enlighter-language语言类型,generic 表示自动识别
data-enlighter-theme单个代码块指定主题,留空表示跟随全局主题
data-enlighter-highlight高亮行,例如 1,3-5
data-enlighter-linenumbers单个代码块是否显示行号,空值表示跟随全局设置
data-enlighter-lineoffset起始行号偏移
data-enlighter-title代码组内展示标题
data-enlighter-group代码组 ID,相同 ID 会合并为同一组

js/gutenberg-extend.js 的块属性与保存结构一一对应:

块属性保存位置编辑器入口
contentcode.gl 文本内容PlainText 代码输入区
c_languagedata-enlighter-language工具栏语言菜单和侧栏语言选择
themedata-enlighter-theme侧栏主题选择,空值为跟随主题
highlightdata-enlighter-highlight侧栏高亮行输入
linenumbersdata-enlighter-linenumbers侧栏行号显示单选
lineoffsetdata-enlighter-lineoffset侧栏起始行号
titledata-enlighter-title代码组标题
groupdata-enlighter-group自定义代码组 ID

块支持从 core/codecore/preformattedcore/paragraph 转换进来,也支持转回 core/codecore/preformatted。粘贴普通 <pre><code> 时,主题会把文本内容带入高亮块;粘贴旧 Enlighter 结构时,也会读取已有的 data-enlighter-* 属性。

经典编辑器里的 precode 按钮使用同一套结构:

<pre contenteditable="false" class="enlighter-pre">
  <code
    class="gl"
    data-enlighter-language="php"
    data-enlighter-theme="dracula"
  >...</code>
</pre>

经典编辑器只提供语言和主题两个字段;古腾堡块额外提供高亮行、行号、起始行号、代码组标题和组 ID。两者前台都进入同一套 EnlighterJS 初始化流程。

扩展时建议遵守这些边界:

需求推荐做法
插入一段可高亮代码保存 pre > code.gl,配置写入 data-enlighter-*
增加更多语言快捷项改编辑器语言列表,同时保持 data-enlighter-language 的值可被 EnlighterJS 识别
做代码组 Tab使用相同 data-enlighter-group,标题写入 data-enlighter-title
控制单块主题data-enlighter-theme;需要跟随全局主题时留空
控制全站滚动高度highlight_maxheight,不要在正文里写死高度
控制复制或扩展按钮highlight_btn 和 Enlighter 工具栏,不要单独在代码块内塞按钮

最小插入示例:

function zib_docs_get_code_block($code, $language)
{
    $language = $language ? $language : 'generic';

    return '<pre><code class="gl" data-enlighter-language="' . esc_attr($language) . '">' . esc_html($code) . '</code></pre>';
}

如果代码内容来自用户输入,必须在服务端转义代码文本和属性值。不要为了保留尖括号而直接输出未过滤 HTML;主题允许的是高亮所需的 data-enlighter-* 属性,不代表代码内容可以跳过 esc_html()

编辑器内预览样式由 css/editor-style.min.csscss/tinymce.css 提供。tinymce.css 会给 .enlighter-pre 设置编辑器内最大高度、滚动条和 code.gl::before 标识;这些只是编辑器提示,不等同于前台最终渲染。前台效果以 EnlighterJS 初始化后的 .enlighter-default 结构为准。

隐藏内容块

zibllblock/hide-content 本质是 [hidecontent] 短代码的编辑器包装。支持的可见模式:

type可见条件
reply评论后可见
logged登录后可见
password输入密码后可见
payshow付费阅读可见
vip1全部会员可见
vip2二级会员可见

密码模式会额外保存 passwordimg_idimg_urldesc。这些字段是引导和校验逻辑的一部分,不能只在编辑器层删除或改名。

隐藏内容不能嵌套使用。扩展时要以服务端短代码回调为准,前端样式只负责展示隐藏状态。

文章、帖子与商品桥接

文章列表块保存:

[postslists cat="1,2" topics="-3" orderby="views" style="minicard" count="12" paginate="ajax"]

参数含义:

参数说明
cat分类 ID,支持英文逗号和负数排除
topics专题 ID,支持英文逗号和负数排除
orderbytitlemodifieddatecomment_countlikeviewsfavoritezibpay_pricezibpay_points_pricesales_volumerand
styletextminicard
count显示数量,分页开启时表示每页数量
paginate空、ajaxnumber

文章/帖子卡片和商品卡片会调用 WordPress REST 搜索辅助选择 ID:

搜索类型保存短代码
文章/帖子postforum_post[postsbox post_id="123"]
商品shop_product[productbox id="456"]

如果站点关闭论坛或商城,前台短代码可能没有对应内容。扩展时应做 post_type_exists()、函数存在性和模块开关检查。

Tab、弹窗与折叠

这些块复用主题和 Bootstrap 风格结构:

触发方式关键点
Tab 栏目.post-tab-toggle + tab-id父块 tabs 管理标题,子块 tab 保存内容
弹窗data-toggle="modal" / href="#modal_id"模态框默认不显示,需要按钮或链接触发
折叠框data-toggle="collapse" + href="#collapse_id"isshow 控制默认展开

新增类似交互块时,优先复用主题已有 class 和前台事件;如果生成了新的 id,要确保同一篇文章内唯一,避免多个弹窗或折叠互相串台。

幻灯片与无缝图

幻灯片块内只允许 core/gallery,保存结构:

<div class="wp-block-carousel">
  <div class="carousel slide" data-effect="fade" data-interval="4000" proportion="0.6">
    <!-- gallery -->
    <div class="swiper-button-next"></div>
    <div class="swiper-button-prev"></div>
    <div class="swiper-pagination"></div>
  </div>
</div>

无缝图同样基于 core/gallery,但保存为 .seamless-img。它更适合商品详情长图、连续图片说明等场景。开启 full-container 后宽度会填满容器,商城内容全屏布局下会有更强的视觉效果。

新增区块的推荐做法

新增块应尽量放在独立插件或子主题资源里,后台只在编辑器页面加载脚本:

function zib_docs_register_editor_block_assets()
{
    if (!function_exists('register_block_type') || _pz('close_gutenberg')) {
        return;
    }

    wp_register_script(
        'zib_docs_editor_blocks',
        get_stylesheet_directory_uri() . '/assets/editor-blocks.js',
        array('wp-blocks', 'wp-element', 'wp-components', 'wp-block-editor'),
        '1.0.0',
        true
    );

    register_block_type('zibll-docs/example', array(
        'editor_script' => 'zib_docs_editor_blocks',
    ));
}
add_action('admin_init', 'zib_docs_register_editor_block_assets');

编辑器脚本示例:

(function (wp) {
  var el = wp.element.createElement
  var RichText = wp.blockEditor.RichText

  wp.blocks.registerBlockType('zibll-docs/example', {
    title: 'Zibll:说明框',
    icon: 'info',
    category: 'zibll_block_cat',
    attributes: {
      content: {
        type: 'array',
        source: 'children',
        selector: '.zib-docs-note',
      },
    },
    edit: function (props) {
      return el(RichText, {
        tagName: 'div',
        className: 'zib-docs-note',
        value: props.attributes.content,
        placeholder: '请输入内容...',
        onChange: function (content) {
          props.setAttributes({ content: content })
        },
      })
    },
    save: function (props) {
      return el(
        'div',
        { className: 'zib-docs-note' },
        props.attributes.content
      )
    },
  })
})(window.wp)

如果块最终依赖服务端渲染,优先保存短代码或最小配置,然后在 PHP 里做权限、查询和缓存:

function zib_docs_shortcode_notice($atts)
{
    $atts = shortcode_atts(array(
        'type' => 'info',
        'text' => '',
    ), $atts);

    $class = in_array($atts['type'], array('info', 'success', 'warning'), true) ? $atts['type'] : 'info';

    return '<div class="alert jb-' . esc_attr($class) . '">' . esc_html($atts['text']) . '</div>';
}
add_shortcode('zib_notice', 'zib_docs_shortcode_notice');

扩展检查清单

  • 后台注册是否尊重 close_gutenberg
  • 区块是否放入 zibll_block_cat
  • 编辑器文案是否可以走本地化,而不是写死在多个脚本里。
  • 保存结构是否复用主题前台已有 class、data-* 和短代码。
  • 服务端是否再次校验权限、登录态、nonce、订单状态和可见条件。
  • 搜索文章、帖子、商品时是否兼容模块未启用的情况。
  • 轮播、视频、弹窗、Tab 是否需要前台 JS 初始化。
  • 动态内容是否避免被页面缓存固定成某个用户的状态。
  • 修改或新增短代码参数后,是否同步编辑器 UI、前台回调和文档。

On this page