本文约 5,817 字,预计阅读 15 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:选项一多,原生写法就开始重复
上篇用 Customizer API 做设置项,三四个字段很清爽;做到第十五个字段时你会发现自己在反复复制 add_setting + add_control 的样板代码,颜色控件还要额外处理 sanitize_hex_color,排版字段(字号、行高、字重、字族)更是得拆成四五个 Setting 才能拼出来。
Kirki 就是在这个位置出现的:它把「注册一个字段」压缩成一次 Kirki::add_field() 调用,内部帮你补上 sanitize、存储、控件渲染,甚至能根据字段值自动输出前台 CSS。对独立开发者来说,它把选项开发从「写架构」变成「填配置」——但代价是引入一个体积不小的依赖,这点后面要单独谈。
原理分析:Kirki 到底替你做了什么
Kirki 本质上是 Customizer API 的封装层,不是另一套存储机制。它仍然把值写进 theme_mod 或 option,你依然用 get_theme_mod() 取值。它的价值集中在四件事:
| 能力 | 原生 Customizer | Kirki |
|---|---|---|
| 字段注册 | add_setting + add_control 两次调用 | 一次 add_field |
| 安全过滤 | 每个字段手写 sanitize_callback | 按控件类型自动匹配 |
| 前台 CSS | 自己写 wp_head 内联样式 | output 参数自动生成 |
| 复杂控件 | 需自行开发 | typography / dimension / repeater / sortable 开箱即用 |
| 依赖体积 | 0 | 约 1MB(含控件脚本与样式) |
output 是 Kirki 最有杀伤力的功能:声明 element(CSS 选择器)和 property(CSS 属性)后,Kirki 会在前台生成一段内联样式,值一改样式就变,省掉自己写 wp_head 的那段代码。它同样支持 units、media_query 和 prefix。
需要注意的是 Kirki 的版本演进:4.x 之后官方推荐以插件形式安装(WordPress.org 的 Kirki Customizer Framework),主题内嵌版本(kirki/kirki.php)虽然仍可用,但会与插件版产生重复加载告警。老项目常见 Kirki::add_config(),新版本命名空间为 Kirki\Compatibility\Kirki,这点在迁移时要留意。
保姆级实操
第一步:安装 Kirki
推荐插件方式,避免主题内嵌带来的合规问题(官方主题目录不允许捆绑强制激活的库):
wp plugin install kirki --activate
若坚持内嵌,用 Composer 拉到主题目录:
cd wp-content/themes/mimangfei
composer require kirki-framework/kirki
然后在 functions.php 顶部引入自动加载:
require_once get_template_directory() . '/vendor/autoload.php';
第二步:配置 config、panel、section
add_action( 'init', 'mimangfei_kirki_config' );
function mimangfei_kirki_config() {
Kirki::add_config( 'mimangfei', array(
'capability' => 'edit_theme_options',
'option_type' => 'theme_mod',
) );
Kirki::add_panel( 'mimangfei_panel', array(
'priority' => 160,
'title' => esc_html__( '主题设置', 'mimangfei' ),
) );
Kirki::add_section( 'mimangfei_typo', array(
'panel' => 'mimangfei_panel',
'title' => esc_html__( '排版', 'mimangfei' ),
'priority' => 10,
) );
}
option_type 可选 theme_mod(默认)或 option,决定值存到哪里。
第三步:常用控件逐个写
Kirki::add_field( 'mimangfei', array(
'type' => 'typography',
'settings' => 'body_typography',
'label' => esc_html__( '正文字体', 'mimangfei' ),
'section' => 'mimangfei_typo',
'default' => array(
'font-family' => 'system-ui',
'font-size' => '16px',
'line-height' => '1.75',
'font-weight' => '400',
),
'output' => array(
array(
'element' => 'body',
),
),
) );
Kirki::add_field( 'mimangfei', array(
'type' => 'dimension',
'settings' => 'container_width',
'label' => esc_html__( '内容区最大宽度', 'mimangfei' ),
'section' => 'mimangfei_typo',
'default' => '1200px',
'output' => array(
array(
'element' => '.container',
'property' => 'max-width',
),
),
) );
Kirki::add_field( 'mimangfei', array(
'type' => 'switch',
'settings' => 'show_breadcrumb',
'label' => esc_html__( '显示面包屑', 'mimangfei' ),
'section' => 'mimangfei_typo',
'default' => true,
'choices' => array(
'on' => esc_html__( '开启', 'mimangfei' ),
'off' => esc_html__( '关闭', 'mimangfei' ),
),
) );
Kirki::add_field( 'mimangfei', array(
'type' => 'sortable',
'settings' => 'single_layout',
'label' => esc_html__( '文章页模块顺序', 'mimangfei' ),
'section' => 'mimangfei_typo',
'default' => array( 'title', 'meta', 'content', 'share' ),
'choices' => array(
'title' => esc_html__( '标题', 'mimangfei' ),
'meta' => esc_html__( '元信息', 'mimangfei' ),
'content' => esc_html__( '正文', 'mimangfei' ),
'share' => esc_html__( '分享按钮', 'mimangfei' ),
),
) );
常用 type 一览:text、textarea、color、image、upload、select、radio、radio-image、checkbox、switch、toggle、slider、number、dimension、spacing、typography、background、repeater、sortable、code、link、multicolor。
第四步:前台取值与兜底
$show_breadcrumb = get_theme_mod( 'show_breadcrumb', true );
if ( $show_breadcrumb ) {
get_template_part( 'template-parts/breadcrumb' );
}
$order = get_theme_mod( 'single_layout', array( 'title', 'meta', 'content', 'share' ) );
Kirki 的 default 只在字段未保存时生效,前台取值仍要写兜底参数——因为主题刚启用、数据库还没写入时,get_theme_mod() 不会自动读 Kirki 的默认值。
第五步:partial refresh 让预览不刷新
Kirki::add_field( 'mimangfei', array(
'type' => 'text',
'settings' => 'footer_text',
'label' => esc_html__( '页脚文字', 'mimangfei' ),
'section' => 'mimangfei_typo',
'default' => esc_html__( '© 2026 迷忙飞', 'mimangfei' ),
'partial_refresh' => array(
'footer_text' => array(
'selector' => '.site-footer__text',
'render_callback' => function() {
echo esc_html( get_theme_mod( 'footer_text', '' ) );
},
),
),
) );
比手写 postMessage 的 JS 省事得多,适合纯文本内容。
常见踩坑
- 插件版与内嵌版同时存在:后台出现重复字段,控制台报 Kirki 多次初始化;二选一。
Kirki::add_config的 id 与取值无关:很多人以为get_theme_mod( 'mimangfei_body_typography' ),实际取值 key 就是settings的值,config id 不参与拼接。option_type改成 option 后旧数据丢失:theme_mod 的历史值不会自动迁移,需要写一次性迁移脚本。output生成的选择器不生效:多因element写成了类名的简写或前台根本没有对应元素,用浏览器审查元素确认选择器命中。- typography 字段返回值是数组:
echo get_theme_mod('body_typography')会报 Array to string conversion,必须取$value['font-size']这样的子项。 - 案例:某主题把 Kirki 内嵌在
inc/目录并强制require,客户站点后来装了 Kirki 插件做其他配置,两个版本控件脚本互相覆盖,Customizer 打开后滑块控件全部失灵。最终改为检测class_exists( 'Kirki' )后再注册,冲突才消失。 - 字段数量过多导致 Customizer 卡顿:超过 60 个字段时建议拆 panel,并关闭不必要的
transport实时刷新。 - 主题上架官方目录不建议内嵌:捆绑库属于「需要额外激活」的灰色地带,建议改为推荐安装插件。
总结
选型判断:字段少于 15 个、类型简单——用原生 Customizer(见 Customizer API 添加设置项);字段多、需要排版/尺寸/排序这类复合控件、且是自用或客户定制项目——Kirki 能省下大量时间;要做上架销售的主题——优先考虑把选项收敛到区块编辑器与 theme.json,或用「按需推荐安装插件」的方式,别把库硬塞进主题包。这一点和 主题选项框架对比 里的取舍逻辑是一致的。
