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

主题小工具与侧栏

扩展子比主题 inc/widgets、小工具注册、页面容器、侧栏位置、CSF 小工具、显示规则和 Ajax 小工具加载。

模块入口

子比主题小工具模块位于 inc/widgets,入口文件是 widget-index.php

zib_require(array(
    'more',
    'posts',
    'user',
    'slider',
    'produck',
    'import',
), false, '/inc/widgets/widget-');
文件作用
widget-class.phpZib_CFSwidget 兼容层、流式侧栏外层处理
widget-index.php注册侧栏位置、页面小工具容器、后台资源、通用 Ajax 小工具入口
widget-more.php图标卡片、视频、iframe、图文封面、按钮、标签云、评论、链接等展示模块
widget-posts.php文章列表、文章 Tab、分类卡片、付费内容、热门文章等
widget-user.php当前用户卡片、作者卡片、用户排行、用户列表
widget-slider.php轮播、图文轮播、封面类模块
widget-produck.php价格方案、评价、FAQ、数据统计、亮点卡片、功能介绍等产品化展示模块
widget-import.php小工具导入导出相关能力

主题同时保留传统 WP_Widget 写法和 Codestar Framework 小工具写法。新的扩展优先使用 Zib_CFSwidget::create()CSF::createWidget(),后台字段更一致,也能复用主题的标题、吸附、显示规则和动画能力。

侧栏位置

主题在 widgets_init 注册基础侧栏:

add_action('widgets_init', 'zib_main_register_sidebar');
add_action('widgets_init', 'zib_main_register_sidebar_2', 99);

主页面类型包括:

页面 key页面
home首页
single文章页
cat分类页
tag标签页
search搜索页

每类页面会生成这些位置:

位置 key说明
top_fluid顶部全宽度
top_content主内容上面
bottom_content主内容下面
bottom_fluid底部全宽度
sidebar侧边栏

此外还有全局位置:

Sidebar id说明
all_top_fluid多数页面顶部全宽度
all_bottom_fluid多数页面底部全宽度
all_sidebar_top多数页面侧边栏顶部
all_sidebar_bottom多数页面侧边栏底部
all_footer底部脚区内部
mobile_nav_fluid移动端弹出菜单底部
newposts_sidebar_top前台投稿侧边栏顶部
newposts_sidebar_bottom前台投稿侧边栏底部

作者页、用户中心、消息中心只注册全宽位置:

页面 key位置
authorauthor_top_fluidauthor_bottom_fluid
useruser_top_fluiduser_bottom_fluiduser_top_content
msgmsg_top_fluidmsg_bottom_fluid

模板输出位置

模板里通过 dynamic_sidebar() 输出侧栏。例如首页:

dynamic_sidebar('all_top_fluid');
dynamic_sidebar('home_top_fluid');
dynamic_sidebar('home_top_content');
dynamic_sidebar('home_bottom_content');
dynamic_sidebar('home_bottom_fluid');
dynamic_sidebar('all_bottom_fluid');

文章页:

dynamic_sidebar('all_top_fluid');
dynamic_sidebar('single_top_fluid');
dynamic_sidebar('single_top_content');
dynamic_sidebar('single_bottom_content');
dynamic_sidebar('single_bottom_fluid');
dynamic_sidebar('all_bottom_fluid');

分类页:

dynamic_sidebar('all_top_fluid');
dynamic_sidebar('cat_top_fluid');
dynamic_sidebar('cat_top_content');
dynamic_sidebar('cat_bottom_content');
dynamic_sidebar('cat_bottom_fluid');
dynamic_sidebar('all_bottom_fluid');

作者页:

dynamic_sidebar('all_top_fluid');
dynamic_sidebar('author_top_fluid');
dynamic_sidebar('author_bottom_fluid');
dynamic_sidebar('all_bottom_fluid');

扩展时先确认模块应该出现在哪个页面和哪个位置。全宽 fluid 位置适合横向模块,sidebar 位置适合窄卡片,不要把依赖大宽度的模块放进窄侧栏。

流式位置外层

widget-class.php 会过滤 dynamic_sidebar_params

function zib_cfswidget_dynamic_sidebar_params($params)
{
    $id = $params[0]['id'];

    if (strstr($id, 'fluid')) {
        $params[0]['before_widget'] = '<div class="widget-container">' . $params[0]['before_widget'];
        $params[0]['after_widget']  = $params[0]['after_widget'] . '</div>';
    }

    return $params;
}
add_filter('dynamic_sidebar_params', 'zib_cfswidget_dynamic_sidebar_params');

所以放在 *_fluid 位置的小工具会额外包一层 .widget-container。自定义小工具不要再重复包相同结构,否则全宽模块容易出现双层边距或布局收窄。

注册侧栏

主题封装了 zib_register_sidebar()

function zib_register_sidebar($sidebars)
{
    $is_preview = is_customize_preview();

    foreach ($sidebars as $value) {
        register_sidebar(array(
            'name'          => $value['name'],
            'id'            => $value['id'],
            'description'   => $value['description'],
            'before_widget' => ($is_preview ? '<div class="customize-preview-widget-box" id="%1$s"><div class="customize-preview-widget-edit">' . esc_html__('编辑', 'zib_language') . '</div>' : '') . '<div class="zib-widget %2$s">',
            'after_widget'  => ($is_preview ? '</div>' : '') . '</div>',
            'before_title'  => '<h3>',
            'after_title'   => '</h3>',
        ));
    }
}

新增侧栏位置时,优先复用这个封装:

function zib_docs_register_resource_sidebar()
{
    $sidebars = array(
        array(
            'name'        => __('资源页-顶部全宽度', 'zib_language'),
            'id'          => 'resource_top_fluid',
            'description' => __('显示在资源页内容顶部位置。', 'zib_language'),
        ),
        array(
            'name'        => __('资源页-侧边栏', 'zib_language'),
            'id'          => 'resource_sidebar',
            'description' => __('显示在资源页侧边栏位置。', 'zib_language'),
        ),
    );

    zib_register_sidebar($sidebars);
}
add_action('widgets_init', 'zib_docs_register_resource_sidebar');

模板里再输出:

if (function_exists('dynamic_sidebar')) {
    echo '<div class="fluid-widget-wrap">';
    dynamic_sidebar('resource_top_fluid');
    echo '</div>';
}

页面专属小工具容器

页面可以通过页面 meta 动态注册专属小工具位置。主题会查询开启 widgets_register 且设置了 widgets_register_container 的已发布页面:

function zib_get_widgets_register_pages()
{
    $cache = wp_cache_get('widgets_register_pages', 'zib_cache_group', true);
    if (false !== $cache) {
        return $cache;
    }

    // 查询 page + widgets_register + widgets_register_container
}

保存页面时刷新缓存:

add_action('save_post_page', 'zib_widgets_register_pages_update_cache');

页面模板根据当前页面 ID 输出:

dynamic_sidebar('page_top_fluid_' . $page_id);
dynamic_sidebar('page_top_content_' . $page_id);
dynamic_sidebar('page_bottom_content_' . $page_id);
dynamic_sidebar('page_bottom_fluid_' . $page_id);

如果扩展页面级容器,不要直接硬编码一批固定页面 ID。应通过页面 meta 或统一注册函数生成,避免页面复制、导入、迁移后失效。

后台资源边界

小工具导入导出、模板导入等后台交互只在 WordPress 小工具页和自定义器里加载:

function zib_wie_localize_admin_script($hook)
{
    if (!in_array($hook, array('widgets.php', 'customize.php'), true)) {
        return;
    }

    wp_enqueue_style('zib_widget_set', ZIB_TEMPLATE_DIRECTORY_URI . '/css/widget-set.min.css', array(), THEME_VERSION);
    wp_enqueue_script('zib_widget_set', ZIB_TEMPLATE_DIRECTORY_URI . '/js/widget-set.min.js', array('jquery'), THEME_VERSION);

    wp_localize_script(
        'zib_widget_set',
        'zib_widget_set_var',
        array(
            'ajaxUrl' => admin_url('admin-ajax.php'),
            'nonce'   => wp_create_nonce('zib_wie_io'),
            'i18n'    => zib_get_widget_js_i18n_strings(),
        )
    );
}
add_action('admin_enqueue_scripts', 'zib_wie_localize_admin_script', 20);

扩展后台小工具交互时,保持这几个边界:

边界说明
页面限制只在 widgets.phpcustomize.php 或确实需要的后台页面加载
Ajax 地址使用 admin_url('admin-ajax.php'),不要硬编码后台路径
Nonce复用或新增明确的 nonce,服务端必须 check_ajax_referer()
文案通过 wp_localize_script() 传递,方便翻译
权限导入导出类操作必须检查 current_user_can('edit_theme_options')

不要把小工具后台脚本全站加载到前台。前台模块需要懒加载时,走 ajax_widget_ui 这类前台 Ajax 协议,而不是复用后台导入导出脚本。

小工具注册方式

主题保留了兼容层:

class Zib_CFSwidget
{
    public static function create($id, $args = array())
    {
        CSF::createWidget($id, $args);
    }
}

常见注册参数:

参数说明
title后台小工具标题
description后台说明
callback前台渲染函数
fieldsCodestar 字段
zib_title是否使用主题标题配置
zib_affix是否支持吸附
zib_show是否支持显示规则
is_show_filter渲染前判断是否显示
size后台字段尺寸倾向

最小写法:

function zib_docs_widget_notice($args, $instance)
{
    $text = !empty($instance['text']) ? $instance['text'] : '';
    if (!$text) {
        return;
    }

    echo '<div class="zib-widget">';
    echo '<div class="box-body">';
    echo esc_html($text);
    echo '</div>';
    echo '</div>';
}

function zib_docs_register_widget_notice()
{
    Zib_CFSwidget::create('zib_docs_widget_notice', array(
        'title'       => __('提示卡片', 'zib_language'),
        'zib_title'   => true,
        'zib_affix'   => true,
        'zib_show'    => true,
        'callback'    => 'zib_docs_widget_notice',
        'description' => __('显示一段简短提示。', 'zib_language'),
        'fields'      => array(
            array(
                'title'   => __('提示内容', 'zib_language'),
                'id'      => 'text',
                'type'    => 'textarea',
                'default' => '',
            ),
        ),
    ));
}
add_action('after_setup_theme', 'zib_docs_register_widget_notice');

主题自己的 CFS 小工具多挂在 after_setup_theme,传统 WP_Widget 多挂在 widgets_init。新增 CFS 小工具建议跟随 after_setup_theme

显示规则

传统小工具会调用:

zib_widget_is_show($instance);

它读取 show_type

说明
all 或空PC 与移动端均显示
only_pc仅 PC 显示
only_sm仅移动端显示

返回值可能是:

返回值含义
true正常显示
false不显示
hidden-xsPC 显示 class
visible-xs-block移动端显示 class

CFS 小工具可以通过 is_show_filter 做渲染前判断,例如作者卡片需要存在当前文章作者,用户卡片需要登录模块未关闭。

示例:

function zib_docs_widget_is_show($show_class, $args, $instance)
{
    if (empty($instance['items'])) {
        return false;
    }

    if (!empty($instance['login_only']) && !is_user_logged_in()) {
        return false;
    }

    return $show_class;
}

注册时:

'is_show_filter' => 'zib_docs_widget_is_show',

不要只在渲染函数里 return 空内容。提前判断可以减少空 .zib-widget 外壳和无意义的布局间距。

标题输出

主题通过 Filter 统一处理小工具标题:

add_filter('zib_widget_title', 'zib_widget_filter_title', 11);

支持字段:

字段说明
title主标题
mini_title副标题
more_but右侧更多按钮文字
more_but_url更多按钮链接

如果小工具使用 zib_title,优先让主题处理标题,不要在渲染函数里重复输出一套标题样式。

通用 Ajax 小工具

主题提供通用 Ajax 入口:

function zib_ajax_widget_ui()
{
    $id          = isset($_REQUEST['id']) ? $_REQUEST['id'] : 0;
    $index       = isset($_REQUEST['index']) ? $_REQUEST['index'] : 0;
    $all_options = get_option('widget_' . $id);

    if (!function_exists($id . '_ajax') || !isset($all_options[$index])) {
        return;
    }

    call_user_func($id . '_ajax', $all_options[$index]);
    exit;
}
add_action('wp_ajax_ajax_widget_ui', 'zib_ajax_widget_ui');
add_action('wp_ajax_nopriv_ajax_widget_ui', 'zib_ajax_widget_ui');

约定:

请求参数说明
action固定为 ajax_widget_ui
id小工具 id base
index当前小工具实例序号

对应函数名必须是:

{id}_ajax

例如文章列表小工具 zib_widget_ui_main_post 会实现:

function zib_widget_ui_main_post_ajax($instance, $no_ajax = false, $ajax_url = null)
{
    // 查询文章、拼接列表、输出 ajaxpager
}

这类 Ajax 入口会读取已保存的小工具实例配置,而不是完全相信前端传入的查询参数。扩展时也应从 get_option('widget_' . $id) 取配置,避免前端随意改分类、数量、排序或付费筛选。

Ajax 列表小工具

文章列表小工具支持 load_mode=ajax,会生成 zib_get_ias_ajaxpager()

$ias_args = array(
    'type'            => 'ias',
    'loader'          => $placeholder,
    'ajaxpager_class' => 'widget-ajaxpager',
    'query'           => array(
        'action' => 'ajax_widget_ui',
        'id'     => $id_base,
        'index'  => $index,
    ),
);
$main_html = zib_get_ias_ajaxpager($ias_args);

非延迟加载时,渲染函数直接返回:

return '<div class="widget-ajaxpager">' . $lists . '</div>';

分页使用主题 Ajax 分页协议:

zib_get_ajax_next_paginate(
    $posts_query->found_posts,
    $paged,
    $paged_size,
    $ajax_url,
    'text-center theme-pagination ajax-pag',
    'next-page ajax-next',
    '',
    'paged',
    'no',
    '.widget-ajaxpager'
);

自定义 Ajax 列表小工具应保持 .widget-ajaxpager.ajax-pag.ajax-next 结构,这样主题前端脚本可以自动接管加载更多和分页替换。

Ajax Tab 小工具

文章 Tab 小工具会为非首个 Tab 生成隐藏触发器:

$con_html .= '<span class="post_ajax_trigger hide"><a ajaxpager-target=".widget-ajaxpager" href="' . add_query_arg('tab', $tabs_key, $ajax_href) . '" class="ajax_load ajax-next ajax-open" no-scroll="true"></a></span>';

Tab 导航使用:

<a data-ajax data-toggle="tab" href="#tab-id">Tab</a>

这和主题通用 Ajax Tab 协议一致。新增 Tab 小工具时,不需要另写一套前端 Tab 加载逻辑,只要输出 data-ajax.post_ajax_trigger.ajax-next 和目标 .widget-ajaxpager 即可。

商城商品小工具

商城商品小工具注册在 inc/functions/shop/widgets/widgets-product.php,属于小工具系统的一组专用实现:

小工具Ajax 行为说明
[商城]商品列表首次输出 zib_get_ias_ajaxpager(),再走 ajax_widget_ui支持分类、优惠活动、标签、排序、分页和商品卡片样式
[商城]多栏目商品列表首个 Tab 懒加载,其他 Tab 用 .post_ajax_trigger 延迟加载每个 Tab 有独立筛选和排序
[商城]单行商品列表不走 Ajax,直接输出 Swiper适合少量横向推荐

这组小工具和普通文章列表小工具的协议相同,但内容容器使用 .product-lists-row,加载占位用 zib_shop_get_lists_card_placeholder(),列表卡片由 zib_shop_get_product_list_card() 输出。筛选条件只从已保存的 widget instance 读取,不应从前端随意传入分类、优惠活动、标签或数量。

更多商品排序、筛选、分页和 Tab 细节见 商城模块 的“商品列表配置”和“商城小工具”。

模块布局组合

子比主题的“页面布局”和“可视化模块”本质上是把页面容器、全宽侧栏、小工具字段、Ajax 分页和动效字段组合起来。开发文档里把它归入小工具体系,是因为源码真正落点在 inc/widgets、页面 meta 和模板 dynamic_sidebar()

常见组合方式:

场景推荐位置常用模块
首页聚合页home_top_fluidhome_top_content幻灯片、图文封面、文章列表、分类卡片、链接列表
单页销售页页面专属 page_top_fluid_{ID}page_bottom_fluid_{ID}价格方案、评价、FAQ、数据统计、按钮组
文章详情页侧栏single_sidebarall_sidebar_top文章目录、付费内容、热门文章、标签云
商城首页商城页面容器或页面专属容器商品列表、商品 Tab、图文封面、服务保障卡片
论坛首页论坛侧栏与论坛小工具用户卡片、帖子列表、版块列表、话题列表
移动菜单扩展mobile_nav_fluid简短按钮、链接、图标入口

模块组合时先定“容器”,再定“小工具”。不要为了一个页面效果新建模板文件,如果页面专属容器和现有小工具能完成,就优先使用页面 meta + 小工具组合,这样后续可以导入导出、复制和在自定义器里预览。

幻灯片与图文视频封面

视觉模块优先使用新版 CFS 小工具。widget-slider.php 里仍然保留了老版 widget_ui_slider,后台标题已经标注“老版即将删除”,新功能不要再把它作为基底;推荐使用 zib_widget_ui_sliderzib_widget_ui_slider_graphic_cover

新版幻灯片小工具的数据分成两层:

字段来源用途
slidesCFS_Module::add_slider()每一张幻灯片的数据,包含背景图、背景视频、文字、按钮、链接和图层类配置
optionCFS_Module::slide()控制轮播方向、按钮、指示器、切换效果、自动高度、PC/移动端高度、间距、速度和自动播放间隔

渲染时主题会把 option.class 固定补成 slide-widget mb20,再把 slides 写入 option.slides,最后交给 zib_new_slider($header_slider_option) 输出。扩展时不要绕过这个入口直接拼 Swiper HTML,否则按钮、分页、视频背景、懒加载和主题统一脚本都要重新维护。

图文视频封面小工具落在 zib_widget_ui_graphic_cover。它的显示判断很严格:首个 coversimagevideo 同时为空时不会输出。常用字段如下:

字段作用
pc_row / m_rowPC 与移动端每行卡片数量,渲染时会转成 Bootstrap 栅格
font_size_pc / font_size_m卡片标题在 PC 与移动端的字号
font_bold / font_color标题粗细与颜色,最终写入 CSS 变量
height_scale卡片高度比例,传给 zib_graphic_card()
mask_opacity封面遮罩透明度
obs_animation / animation_repeat入场动画与是否重复播放
covers[]每张封面卡片的数据组

covers[] 单项支持这些字段:

字段作用
image图片兜底,也是移动端最稳定的封面来源
video视频封面,传给 zib_graphic_card() 输出
title卡片居中文案,会进入 more 字段
link卡片跳转地址
hide按 PC 或移动端隐藏,渲染时通过 wp_is_mobile() 判断

视频封面不要只填 video。移动端浏览器对自动播放、静音、节能策略限制更多,主题的图文封面也会优先依赖图片兜底;只配置视频时,移动端可能出现空封面或首帧不可控。

zib_widget_ui_slider_graphic_cover 是“左侧幻灯片 + 右侧图文视频卡片”的组合模块,适合首页、频道页、商城入口和专题页的首屏区域。核心字段如下:

字段作用
layout_ratio幻灯片宽度占比,右侧卡片宽度由剩余空间计算
slide_scale幻灯片长宽比,组合模块会强制 scale_height = true
pc_row / pc_col右侧封面卡片的列数与行数
m_layout_type移动端布局:保持 PC、上下布局、隐藏幻灯片、隐藏卡片
m_row / m_cover_ratio移动端卡片列数与比例
slides / option左侧幻灯片数据与轮播选项
covers / mask_opacity右侧图文视频卡片与遮罩
obs_animation / animation_repeat整体入场动画

组合模块会根据 layout_ratioslide_scalepc_rowpc_col 自动计算右侧卡片比例,并写入 --layout-ratio--cover-ratio--m-cover-ratio。前端还会在 wp_footer 只输出一次校准脚本,根据真实 .zib-slider 高度和 .cover-col 宽度重新修正 --cover-ratio,所以不要在扩展里把内部结构改成不含 .slider-col.cover-col.zib-slider 的 DOM。

如果只想复用图文视频卡片 HTML,而不是直接 echo,可调用主题提供的返回版函数:

function zib_docs_render_feature_covers($covers)
{
    if (empty($covers) || !function_exists('zib_widget_slider_graphic_cover_html')) {
        return '';
    }

    $instance = array(
        'pc_row'        => 3,
        'm_row'         => 1,
        'height_scale'  => 60,
        'mask_opacity'  => 30,
        'font_size_pc'  => 16,
        'font_size_m'   => 14,
        'font_bold'     => true,
        'font_color'    => '#ffffff',
        'covers'        => $covers,
    );

    return zib_widget_slider_graphic_cover_html($instance);
}

这类模块更适合放在 *_fluid 或页面专属全宽容器里。窄侧栏可以使用单列图文封面、按钮组或链接列表,不建议放组合模块,否则比例计算虽能工作,视觉上也容易挤压。

全宽模块

全宽模块适合承载视觉模块、横向卡片、幻灯片和专题介绍。源码会给 fluid 位置自动加 .widget-container,所以小工具渲染函数只输出模块本体即可:

function zib_docs_widget_banner($args, $instance)
{
    $title = !empty($instance['title']) ? $instance['title'] : '';
    $image = !empty($instance['image']) ? $instance['image'] : '';

    if (!$title && !$image) {
        return;
    }

    echo '<div class="zib-widget zib-docs-banner">';
    if ($image) {
        echo '<div class="banner-cover">';
        echo '<img src="' . esc_url($image) . '" alt="' . esc_attr($title) . '">';
        echo '</div>';
    }
    if ($title) {
        echo '<div class="banner-title">' . esc_html($title) . '</div>';
    }
    echo '</div>';
}

如果模块放在窄侧栏,宽图、横向 Swiper、四列卡片都要降级。可以通过字段控制列数,或在 is_show_filter 中只允许全宽位置显示。

页面专属模块

页面专属容器适合“普通页面改成专题页”。后台页面开启 widgets_register 后,主题会按 widgets_register_container 动态注册:

page_top_fluid_{ID}
page_top_content_{ID}
page_bottom_content_{ID}
page_bottom_fluid_{ID}
page_sidebar_{ID}

这类容器不要写死在扩展插件里。正确做法是读取当前页面 ID,再按约定输出:

function zib_docs_page_widgets($page_id)
{
    if (!$page_id) {
        return;
    }

    dynamic_sidebar('page_top_fluid_' . $page_id);
    dynamic_sidebar('page_top_content_' . $page_id);
}

页面被复制或迁移后,ID 可能变化。需要可迁移能力时,用导入模板重新装配页面模块,不要依赖旧站点的固定 ID。

导入导出数据

widget-import.php 提供单个侧栏导出和导入能力。导出结构不是普通文章数据,而是 WordPress 小工具实例与侧栏占位符的组合:

array(
    'export_version'      => 1,
    'exported_at'         => gmdate('c'),
    'source_sidebar_id'   => $sidebar_id,
    'source_sidebar_name' => $sidebar_name,
    'theme_name'          => $theme->get('Name'),
    'theme_version'       => $theme->get('Version'),
    'widgets'             => $widget_list,
    'widget_options'      => $widget_options,
);
字段作用
widgets当前侧栏里的小工具占位符列表,例如 zib_widget_ui_main_post-3
widget_optionsid_base 分组的小工具实例配置
_multiwidgetWordPress 多实例小工具标记,导入时需要保留
source_sidebar_id原始侧栏 ID,只用于记录来源,不代表导入目标

导入时不要把旧占位符直接写入目标侧栏。主题会解析 id_base-number,为当前站点重新分配实例序号:

function zib_wie_parse_widget_id($widget_id)
{
    if (!is_string($widget_id) || $widget_id === '') {
        return null;
    }
    if (!preg_match('/^(.+)-(\d+)$/', $widget_id, $m)) {
        return null;
    }

    return array(
        'id_base' => $m[1],
        'number'  => (int) $m[2],
    );
}

zib_wie_run_import() 支持两种模式:

模式行为
replace清空目标侧栏,只保留导入的小工具
append在目标侧栏现有小工具后追加导入项

导入流程会检查当前站点是否已注册对应 id_base。如果目标站点缺少某个小工具,返回值里的 missing_bases 可以用于提示用户先启用对应模块或插件。

侧栏模板注册

主题内置模板走 widget_import_templates 过滤器。模板可以是紧凑格式,按顺序列出小工具 id_base 和默认实例:

function zib_docs_register_widget_templates($templates)
{
    $templates['docs_landing_01'] = array(
        'title'   => __('文档首页模块组合', 'zib_language'),
        'desc'    => __('适合放在页面顶部全宽度位置。', 'zib_language'),
        'remind'  => __('导入前建议先备份当前侧栏。', 'zib_language'),
        'widgets' => array(
            array(
                'id'       => 'zib_widget_ui_graphic_cover',
                'instance' => array(
                    'title'        => __('核心能力', 'zib_language'),
                    'show_type'    => 'all',
                    'animation_in' => 'slideup',
                    'pc_row'       => '3',
                    'm_row'        => '1',
                    'covers'       => array(),
                ),
            ),
            array(
                'id'       => 'zib_widget_ui_main_post',
                'instance' => array(
                    'title'     => __('最新内容', 'zib_language'),
                    'load_mode' => 'ajax',
                    'orderby'   => 'modified',
                    'order'     => 'desc',
                    'style'     => 'card',
                    'count'     => '12',
                    'paginate'  => 'ajax',
                ),
            ),
        ),
    );

    return $templates;
}
add_filter('widget_import_templates', 'zib_docs_register_widget_templates');

模板导入前会把紧凑格式转换成完整导入数据:

function zib_wie_compact_template_to_import_data($def)
{
    // widgets: array(
    //     array('id' => 'id_base', 'instance' => array()),
    // )
}

写模板时注意:

项目建议
id必须是已注册小工具的 id_base
instance优先使用数组;字符串 JSON 只适合复制已有配置
动画字段使用主题字段,例如 animation_inanimation_repeat
标题字段保持 titlesubtitletitle_link 等主题字段
布局字段保留 layout_pin_pclayout_pin_mlayout_bg 这类模块布局字段
目标位置descremind 里明确建议导入到哪个侧栏

不要在模板里写死生产站图片、用户头像、订单、邀请码、私有接口地址或一次性文件 URL。模板应该表达布局结构,不应该携带站点隐私数据。

导入导出 Ajax

后台导入导出入口都在 admin-ajax.php

Action函数作用
zib_wie_list_templateszib_wie_ajax_list_templates()列出可导入模板和模块预览
zib_wie_import_templatezib_wie_ajax_import_template()将已注册模板导入指定侧栏
zib_wie_export_sidebarzib_wie_ajax_export()导出指定侧栏 JSON
zib_wie_import_sidebarzib_wie_ajax_import()从 JSON 文本导入指定侧栏

每个入口都要做两件事:

check_ajax_referer('zib_wie_io', 'nonce');

if (!current_user_can('edit_theme_options')) {
    wp_send_json_error(array('message' => __('权限不足', 'zib_language')), 403);
}

新增自己的模板管理入口时,响应格式保持主题习惯:

wp_send_json_success(array(
    'imported'    => (int) $result['imported'],
    'sidebar_id'  => $target,
    'import_mode' => $import_mode,
    'warnings'    => $warnings,
    'message'     => $message,
));

这类接口只给后台管理员使用,不要注册 nopriv 版本,也不要把原始 JSON 解析错误、服务器路径、完整 PHP 异常栈直接返回前端。

小工具分类

主题现有小工具大致分为:

类型代表
内容列表主文章列表、文章 Tab、单行文章、热门文章、付费商品
分类展示分类卡片、分类列表卡片、标签云
用户展示登录用户卡片、作者卡片、用户排行、用户列表
媒体展示轮播、图文封面、视频、iframe
营销展示价格方案、评价、FAQ、数据统计、亮点卡片、功能介绍
导航辅助图标卡片、按钮组、链接列表、文章目录、搜索

开发新小工具前先判断是否能通过现有小工具字段组合实现。只有现有模块无法表达业务结构时,再新增小工具。

扩展建议

需求推荐入口
新增展示模块Zib_CFSwidget::create()
新增页面侧栏位置zib_register_sidebar() + 模板 dynamic_sidebar()
按页面注册专属容器页面 meta + zib_page_register_sidebar() 思路
控制模块是否显示is_show_filterzib_widget_is_show()
小工具延迟加载ajax_widget_ui + {id}_ajax
小工具列表分页.widget-ajaxpager + zib_get_ajax_next_paginate()
小工具 Tab 异步加载data-ajax + .post_ajax_trigger
统一标题zib_widget_title
模块布局模板widget_import_templates
侧栏迁移zib_wie_build_export() + zib_wie_run_import()

风险清单

  • 不要把大宽度模块放进窄侧栏。
  • 不要在 *_fluid 位置重复包 .widget-container
  • 不要让前端 Ajax 参数直接决定查询范围,应读取已保存的小工具配置。
  • 不要输出空 .zib-widget,先用 is_show_filter 判断。
  • 不要在小工具里直接 echo 未转义的后台字段。
  • 不要把查询类小工具整页缓存成静态 HTML,分类、分页、登录态和付费状态都可能变化。
  • 不要在每个小工具里重复加载脚本,尽量通过统一 enqueue 或只在需要时挂 wp_footer
  • 不要直接编辑 sidebars_widgets 里的旧小工具占位符,导入时必须重新分配实例号。
  • 不要把导入导出接口开放给未登录用户或普通订阅者。
  • 不要在生产代码里保留打印 $wp_widget_factory->widgets、导出 JSON、服务器路径等调试日志。
  • 不要把模块模板当成数据备份系统,订单、用户、媒体授权、支付配置都不属于小工具模板。

On this page