给插件加个后台页:Config 存条数与标题
给插件加后台配置页,不用自己建表:Z-Blog 自带 $zbp->Config('插件ID') 一个插件一个命名空间,读两行写两行,但 SaveConfig 一次都不能漏,Config 从未创建时读出来是 null 而非空串,必须带默认值兜底。文中给出 main.php 最小骨架(三层 require、CheckRights、CheckIsRefererValid、SetHint 配 Redirect),前台 include.php 读配置的写法,以及三个实际踩过的坑:Config 名必须与插件 ID 完全一致否则禁用启用后配置丢失、$_POST 数字存成字符串导致 SQL 语法错误、漏写权限判断让非管理员能改配置。
上一篇把「文末相关文章」收成了插件,能开关了。但紧接着就有人问我:条数想改怎么办?标题想换成「你可能也喜欢」怎么办?
我当时的回答是「改 include.php 里的常量」——说完自己都觉得不像话,一个装上去给非技术人用的插件,改条数还要动源码,这也太离谱了。
所以这篇就干一件事:给它加个后台配置页。三四十行代码,不复杂,但坑比想象的多。
先说结论:配置不用自己建表
这是我第一次写插件时最大的误解——以为要自己 CREATE TABLE。实际上 Z-Blog 自带 $zbp->Config,一个插件一个命名空间(一般就是插件 ID),存的东西会序列化进 c_option.php 对应的键里,读写都只两行:
// 读
$count = (int) $zbp->Config('MyPlugin')->count;
// 写
$zbp->Config('MyPlugin')->count = 5;
$zbp->SaveConfig('MyPlugin');
注意第二段那个 SaveConfig,忘了写就白改。我第一次调的时候在后台点了十几次保存都没生效,最后发现是漏了这一行——不报错,特别隐蔽。
还有个更隐蔽的:如果这个插件的 Config 从来没被创建过,读出来是 null,不是空字符串、不是 0。所以永远要带默认值兜底:
$count = (int) ($zbp->Config('MyPlugin')->count ?: 5);
后台页挂在哪
两种做法,我两种都试过:
| 我要干什么 | 用哪个 | 注意 |
|---|---|---|
| 就一个设置页,简单几项 | 插件目录放 main.php,然后在 plugin.xml 里不写 admin,Z-Blog 自动把 main.php 当设置页 | 最简单,我就是用这个 |
| 要多个页面 / 列表 / 分页 | Filter_Plugin_Admin_SettingMng_SubMenu 挂子菜单,自己写页面文件 | 容易因为菜单 key 冲突打不开 |
我选第一种,因为就两个字段。如果你选第二种,记住一件事:子菜单的 key 不能跟你插件的其它菜单重名,不然点进去是白屏,也不报错。
main.php 怎么写
骨架大概是这样,重点是那个 header 和 footer,不 include 的话页面会变成裸 HTML,样式全丢:
<?php
require '../../../zb_system/function/c_system_base.php';
require '../../../zb_system/function/c_system_admin.php';
$zbp->Load();
if (!$zbp->CheckRights('root') && !$zbp->CheckRights('admin')) {
$zbp->ShowError(6);
die();
}
$cfg = $zbp->Config('MyPlugin');
// 保存
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
CheckIsRefererValid();
$cfg->count = (int) $_POST['count'];
$cfg->title = trim($_POST['title']);
$zbp->SaveConfig('MyPlugin');
$zbp->SetHint('good', '保存成功');
Redirect('./main.php');
}
require $zbp->path . 'zb_system/admin/admin_header.php';
require $zbp->path . 'zb_system/admin/admin_footer.php';
?>
三个地方容易翻车:
require那几行的相对路径。main.php在zb_users/plugin/MyPlugin/下,所以要退三层回到根目录。少退一层就是白屏。CheckIsRefererValid()别省,省了后台 POST 会被拦,表现为「点保存没反应」,什么都不提示。$zbp->SetHint加Redirect是配套的,光 SetHint 不跳转的话提示不会显示。
前台那头怎么读
后台存进去,前台 include.php 里读出来用就行,别每次查询都重新读一次 Config:
function MyPlugin_Article_Content(&$article) {
global $zbp;
$cfg = $zbp->Config('MyPlugin');
$count = (int) ($cfg->count ?: 5);
$title = $cfg->title ?: '相关文章';
// ... 后面查文章、拼 HTML
}
global $zbp 别忘。忘了就是「未定义变量」,然后整个页面 500,你会在错误日志里看到一行 fwrite 警告,找半天。
我踩的三个坑
第一个:Config 名字必须跟插件 ID 完全一致。我复制了别人的代码,那里写的是 Config('Demo'),我以为是随便起的名字,结果存进去了、后台也能读到,但插件目录名叫 MyPlugin,禁用再启用之后配置全丢了——因为 Z-Blog 卸载/启用时会按插件 ID 去砍 Config,名字对不上的就不归它管。
第二个:数字字段存成了字符串。$_POST['count'] 永远是字符串,直接塞进 Config,前台拿去 LIMIT '5',报 SQL 语法错误。必须 (int) 转一下。
第三个:忘了判断权限。第一版我没写 CheckRights,那段时间前台页面是好的,但非管理员直接访问 main.php 就能把配置改掉。这个失误我不想细说,你记得加那一行就行。
到这儿插件算完整了
回过头看这四篇:从「钩子是什么」,到「挂在哪」,到「拿到的东西怎么用」,再到「收成能装的插件」,最后今天这个后台页。一条线下来了。
下一篇我想换个方向,不回钩子了——写写分类和 URL 那块。因为我现在这个站,分类一层套一层,post/11.html 这种地址看着也挺素,想聊聊分类父子关系怎么取,以及伪静态规则到底怎么配——{%page%} 为 1 的时候为什么整段从地址里消失、尾斜杠什么时候该带。
你要是正卡在某一步,就把「哪个页、想看到什么、现在实际是什么」三句话丢在评论里,我照着帮你对。