给插件加个后台页:Config 存条数与标题

· zblog · 阅读 70
摘要

给插件加后台配置页,不用自己建表: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 的时候为什么整段从地址里消失、尾斜杠什么时候该带。

你要是正卡在某一步,就把「哪个页、想看到什么、现在实际是什么」三句话丢在评论里,我照着帮你对。