2.1 插件模块三类型与挂载位置

把功能挂到导航、挂到用户页、还是插进现有页面,看这一节就能选对。

模块是什么,谁来挂

插件本身只是一堆躺在 source/plugin/标识符/ 里的 PHP 文件,Discuz! 不会自动执行它们。真正把它们叫醒的是插件模块机制:后台插件详情页分三块设置,每块配置「在什么位置、按什么身份、调用哪个文件」。差别本质是挂载目标不同:挂导航条、挂已有设置页、挂系统脚本的执行点。

类型 挂到哪里 脚本后缀 典型用途
程序链接 导航、菜单 .inc.php 加一个入口页
扩展项目 用户中心、后台固定栏 .inc.php 在已有页面插入一块
程序脚本 系统脚本执行过程 .class.php 不新增页面,改现有行为

打个比方:程序链接是新开一扇门,扩展项目是在墙上开一扇窗,程序脚本是在水管上装过滤器。

一个程序链接类模块的最简文件形态,就是模块名加后缀:

<?php
// source/plugin/hello/hello.inc.php  ← 后台模块名填 hello
defined('IN_DISCUZ') or exit('Access Denied');
$msg = 'Hello, Discuz!';
include template('hello');

模块名必须和 .inc.php 的文件名一字不差,这是 404 的头号来源。

类型一:程序链接类

这一类负责把插件挂到站点的导航体系上,后台能配的位置有:

挂载位置 出现的地方
主导航项目 站点顶部主导航
主导航-插件菜单 主导航某项的二级菜单
顶部导航项目 顶部导航条
底部导航项目 页脚导航
快捷导航项目 快捷导航区
家园导航项目 家园(个人空间)导航

每个位置可以指派两种目标:一个 URL,或者调用一个插件模块。选了后者,后台让你填模块名,对应 source/plugin/{标识}/{模块名}.inc.php。模块名填 hello,就找 source/plugin/hello/hello.inc.php,生成的链接是 plugin.php?id=标识:模块名。

类型二:扩展项目类

扩展项目不新增页面,而是挂到系统已有的固定位置上。脚本同样以 .inc.php 结尾,但模板是固定文件名,放在 source/plugin/{标识}/template/ 子目录里,与脚本同名。后台提供的挂载位置共 10 个:

序号 挂载位置 出现在
1 个人设置 用户中心 → 设置
2 个人资料 用户中心 → 资料
3 个人积分 用户中心 → 积分
4 站点帮助 帮助类页面
5 我的帖子 用户中心 → 帖子
6 门户管理 门户后台
7 论坛管理-基本 后台 → 论坛 → 基本
8 论坛管理-工具 后台 → 论坛 → 工具
9 管理中心 后台插件栏新增管理模块
10 管理中心-列表链接 管理中心的远程链接(X3.1 起)

「固定文件名 + 与脚本同名」这条最容易踩坑。脚本叫 mytools.inc.php,模板就必须是 template/mytools.htm。写错的表现是页面一片空白,控制台没有任何提示。

类型三:程序脚本类

程序脚本不负责出页面,而是插进系统脚本的执行过程里:

挂载位置 说明
页面嵌入(普通版) 桌面版模板里的 {hook/钩子名}
页面嵌入(手机版) 手机版模板里的同名钩子
特殊主题 帖子特殊主题标识(投票、悬赏那一套)

脚本以 .class.php 结尾,写成一个类,类名和钩子名有严格对应关系。普通版用 plugin_ 前缀,手机版用 mobileplugin_ 前缀。完整骨架与调用时机见 2.3、2.4。

三类模块对照

横向比一次:程序链接和扩展项目都用 .inc.php,区别在于前者的模板名你自己定(通过 include template() 指定),后者是固定名放在 template/ 子目录。前两者都是「用户点进来才执行」,程序脚本是「系统在执行点自动调用」,不写模板。

决策表:我想把功能挂哪儿

我要做的事 选哪类 挂在哪
加一个独立页面(兑换、抽奖、工具箱) 程序链接 主导航项目
只给管理员用的操作面板 程序链接 主导航项目 + 使用等级
在用户中心加一块设置 扩展项目 个人设置
在用户资料页加自定义内容 扩展项目 个人资料
在后台加一个配置页 扩展项目 管理中心
给帖子内容前后加东西 程序脚本 页面嵌入 + 对应钩子
统计或拦截删除操作 程序脚本 页面嵌入 + 删除类钩子
改写提示文案、拦截输出 程序脚本 页面嵌入 + 消息与输出类钩子
只是个跳转,不需要页面 程序链接 填 URL,不选模块

口诀:要出页面用 .inc.php,不出页面插钩子用 .class.php。

使用等级不等于权限校验

每个模块都能在后台设一个「使用等级」,比如超级版主、管理员。但这个设置只是菜单层面的显示与初步过滤,程序内部仍需自行校验权限。

原因很直接:用户可以手工构造 URL 访问模块。菜单里看不见入口,不代表 URL 打不开。所以模块脚本第一件事是查身份:

<?php
if (!defined('IN_DISCUZ')) {
    exit('Access Denied');
}

// $_G['uid'] 非 0 即已登录;$_G['adminid'] 1~3 为管理身份
if (!$_G['adminid']) {
    showmessage('抱歉,您没有权限使用此功能');
}

这段放在 source/plugin/标识/模块名.inc.php 的开头。少这一行,模块就等于对全站注册用户开放。

常见坑

现象 原因 处理
后台模块保存后前台不显示 插件未启用或缓存没更新 启用插件;更新缓存
扩展项目页面空白无报错 模板文件名不对 严格按 template/与脚本同名.htm
页面出现裸 PHP 源码 模板没走 template() 一律用 include template()
菜单点进去 404 模块名和文件名不一致 模块名 = .inc.php 的文件名
手机版没有效果 只写了 plugin_ 类 补 mobileplugin_ 类
普通用户也能打开管理页 只靠后台等级设置 模块内校验 $_G['adminid']

小结

三类模块对应三种意图:程序链接新开门,扩展项目开窗,程序脚本装过滤器。选型只看一件事——这功能需不需要自己出一张页面。需要就 .inc.php,在导航或扩展位置上挂;不需要就 .class.php,去找对应钩子点。

再强调一次最容易翻车的规则:后台的使用等级只是菜单过滤,权限判断必须写在你自己的模块文件里。

2.2 讲最省事的落地方式:文件一放,plugin.php 直接就能访问。