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

保存流程与备份链路

拆解子比主题 CSF 设置保存、Ajax 保存、reset、导入、自动备份、缓存刷新和 WordPress 选项同步流程。

保存入口

后台主题设置保存由 inc/csf-framework/classes/admin-options.class.php 处理。核心方法是:

public function set_options($ajax = false)
public function save_options($data)

Ajax 保存入口来自:

add_action('wp_ajax_csf_' . $this->unique . '_ajax_save', array(&$this, 'ajax_save'));

对子比主题来说,$this->unique 是:

zibll_options

因此 Ajax action 是:

csf_zibll_options_ajax_save

set_options 的执行顺序

set_options() 不是简单接收 $_POST 后写入数据库。它按这个顺序处理:

顺序动作说明
1读取请求Ajax 从 $_POST['data'] 解析 JSON,普通提交读取 $_POST
2校验 noncenonce key 为 csf_options_nonce{$unique}
3判断导入/重置支持导入、重置全部、重置当前 section
4遍历字段pre_fields 收集所有带 id 的字段
5处理值读取提交值,必要时 wp_unslash()
6sanitize按字段 sanitize 配置处理
7validate如果字段有 validate callable,失败则回滚旧值并记录错误
8保存前 Hookcsf_{$unique}_save_before
9保存过滤csf_{$unique}_save
10写数据库save_options($data)
11保存后 Hookcsf_{$unique}_save_after

理解这个顺序后,很多问题会变清楚:字段没有提交时会保存为空;验证失败会回到旧值;导入和 reset 会绕过普通提交值。

子比对 sanitize 的改动

子比覆盖后的 admin-options.class.php 里有一段注释:

//修改:移出sanitize,允许全部保存html代码
if (!isset($field['sanitize'])) {
    $data[$field_id] = $field_value;
} else if (isset($field['sanitize']) && is_callable($field['sanitize'])) {
    $data[$field_id] = call_user_func($field['sanitize'], $field_value);
} else {
    $data[$field_id] = $field_value;
}

这意味着:

  • 没写 sanitize 的字段,保存时不会默认 wp_kses_post()
  • 写了 callable 的 sanitize 才会按自定义函数过滤。
  • HTML 字段可以保存完整内容,但前台输出必须按场景转义。

常见输出边界:

内容输出方式
普通文本esc_html()
URLesc_url()
属性esc_attr()
后台可信 HTMLwp_kses_post() 或主题白名单
JSON 配置wp_json_encode() 后输出
JS 字符串不直接拼接,使用本地化变量或严格转义

所以字段“保存 HTML”不等于“前台原样 echo”。保存策略和输出策略是两件事。

save_options 写入位置

save_options() 会根据 database 参数决定保存位置:

if ($this->args['database'] === 'transient') {
    set_transient($this->unique, $data, $this->args['transient_time']);
} else if ($this->args['database'] === 'theme_mod') {
    set_theme_mod($this->unique, $data);
} else if ($this->args['database'] === 'network') {
    update_site_option($this->unique, $data);
} else {
    update_option($this->unique, $data);
}

do_action("csf_{$this->unique}_saved", $data, $this);

子比主题全站设置使用默认 options 数据库,因此最终写入:

wp_options.option_name = zibll_options

前台读取统一用:

_pz('field_id', $default);

reset 与导入

CSF 支持三种非普通保存路径:

动作触发条件结果
导入csf_import_data使用导入 JSON 覆盖 $options
重置全部csf_transient[reset]所有字段回到默认值
重置分区csf_transient[reset_section] + section id当前 section 字段回到默认值,并与旧配置合并

子比主题在 reset 前增加了备份 Hook:

add_action('csf_zibll_options_reset_before', 'zib_csf_reset_to_backup');
add_action('csf_zibll_options_reset_section_before', 'zib_csf_reset_section_to_backup');

因此重置前会把当前 zibll_options 保存到 zibll_options_backup

自动备份

inc/options/options.php 里有统一备份函数:

function zib_options_backup($type)

备份数据结构大致是:

$options_backup[$time] = array(
    'time' => $time,
    'type' => $type,
    'data' => $options,
);

备份最多保留 20 次。触发来源:

触发类型
重置全部前重置全部 自动备份
重置选区前重置选区 自动备份
主题更新时更新主题 自动备份
设置保存后定期定期自动备份

定期自动备份通过:

add_action('csf_zibll_options_saved', 'zib_csf_save_section_to_backup');

它会查最近一次 定期自动备份,超过约 600 小时才新增一份,避免每次保存都堆积备份。

保存后的同步

主题设置保存后还会执行:

add_action('csf_zibll_options_save_after', 'zib_save_zibll_wp_options');

zib_save_zibll_wp_options() 做两类事:

场景行为
首次安装写入评论分页、评论顺序、邮箱名称要求、嵌套评论、媒体尺寸等 WordPress 选项
每次保存更新 Zibll_version,执行 zib_flush_rewrite_rules()

这说明某些设置保存后会影响站点固定链接和 WordPress 基础选项。开发或排错时,如果设置保存后前台链接仍不对,要同时考虑 rewrite 规则和缓存。

模块缓存刷新

保存 zibll_options 还会被其他模块监听:

add_action('csf_zibll_options_saved', 'zib_search_facets_datas_cache_delete');
add_action('csf_zibll_options_saved', 'zib_medal_args_cache_set');

典型含义:

  • 高级筛选配置变化后,搜索筛选缓存需要删除。
  • 用户徽章配置变化后,徽章参数缓存需要重建。

如果新增字段会影响派生数据,也应该挂到 csf_zibll_options_saved 或更精准的业务 Hook,而不是要求用户手动清缓存。

Meta 保存 Hook

不同 CSF 类型有不同保存 Hook 参数:

类型Hook 形态额外参数
Optionscsf_{$unique}_savecsf_{$unique}_saved$data, $this
Metaboxcsf_{$unique}_savecsf_{$unique}_saved$data, $post_id, $this
Taxonomycsf_{$unique}_savecsf_{$unique}_saved$data, $term_id, $this
Profilecsf_{$unique}_savecsf_{$unique}_saved$data, $user_id, $this
Nav Menucsf_{$unique}_savecsf_{$unique}_saved$data, $menu_item_db_id, $this
Widgetcsf_{$unique}_save$new_instance, $args, $this

写 Hook 时先确认 $unique 和参数数量。拿 options 的 Hook 写法去接 taxonomy 或 nav menu,参数会错。

什么时候挂保存 Hook

适合挂保存 Hook 的情况:

  • 保存后需要删除缓存。
  • 保存后需要刷新 rewrite rules。
  • 保存后需要同步一份派生配置。
  • 保存前要统一纠正字段结构。
  • 保存前要阻止非法组合值。

不适合挂保存 Hook 的情况:

  • 只是前台展示判断,用 _pz() 即可。
  • 只是字段显示隐藏,用 dependency 即可。
  • 只是单个用户/文章业务动作,应走对应 Ajax 或业务函数。
  • 涉及支付订单、余额、会员、积分时,应走业务流程,不要只改 CSF 保存数据。

保存问题排查

按这个顺序查:

  1. 请求是不是 csf_zibll_options_ajax_save 或主题设置页普通提交。
  2. nonce 是否通过。
  3. 字段是否存在于 pre_fields
  4. 字段 id 是否随表单提交。
  5. 字段是否被 validate 回滚。
  6. csf_zibll_options_save filter 是否改写了值。
  7. update_option('zibll_options') 是否成功。
  8. _pz() 的静态缓存是否在同一次请求里已经提前读取。
  9. 保存后相关缓存、rewrite、派生数据是否刷新。

On this page