Typecho 默认使用 admin 作为后台目录。出于部署习惯,有些站点会在上线后修改这个目录名。如果插件后台页面在本地显示正常,上线后却丢失顶部导航、页面宽度和表单样式,而插件自己的布局仍然存在,问题往往不在 CSS 内容本身,而在插件加载后台公共模板的方式。
本文记录一次完整的定位和修复过程,并给出一种同时兼容默认后台目录与自定义后台目录的写法。

问题现象
同一个插件页面在两个环境中出现了明显差异:
- 本地环境使用默认的
admin目录,后台顶部导航、居中容器、按钮和输入框样式都正常。 - 线上环境修改了后台目录名,页面只剩插件自身的双栏、边框和标签页样式。
- 线上页面的字体更大,链接恢复为浏览器默认的蓝色下划线,内容也不再居中限宽。
- 页面功能主体仍能输出,没有直接显示致命错误。
这些特征说明插件自己的 admin.css 已经加载,但 Typecho 后台的 normalize.css、grid.css 和 style.css 没有进入页面。同时,后台菜单模板也没有正常输出。
从资源路径缩小范围
Typecho 后台公共样式由后台的 header.php 输出,资源地址通过 $options->adminStaticUrl() 生成。插件自己的静态资源通常通过 $options->pluginUrl 生成。
这两类资源使用不同的入口:
后台公共资源:/<后台目录>/css/style.css
插件静态资源:/usr/plugins/<插件名>/assets/admin.css因此,出现“插件样式还在、后台外壳消失”的情况时,应优先检查下面两项:
- 页面是否成功包含了后台的
header.php和menu.php。 - 浏览器开发者工具中,后台公共 CSS 的地址和响应状态是否正确。
根本原因:插件写死了 admin 目录
问题插件使用了下面这种模板加载方式:
include __TYPECHO_ROOT_DIR__ . '/admin/header.php';
include __TYPECHO_ROOT_DIR__ . '/admin/menu.php';页尾的 copyright.php、common-js.php 和 footer.php 也使用了相同的硬编码路径。
本地后台目录就是 admin,所以问题不会暴露。线上将后台目录改名后,PHP 仍然尝试读取 <站点根目录>/admin/header.php,文件自然不存在。
这里使用的是 include。文件包含失败时 PHP 会产生警告,但脚本通常还会继续执行。生产环境关闭错误显示后,管理员看不到警告,只会看到插件主体被输出,而后台页头、菜单、公共样式和脚本全部缺失。这正是页面看起来“只坏了一半”的原因。
正确读取 Typecho 后台目录
Typecho 使用 __TYPECHO_ADMIN_DIR__ 表示后台目录。插件不应该假设它一定是 /admin/,而应根据该常量构造后台模板的文件系统路径。
可以为插件增加一个专用的路径函数:
function plugin_admin_file(string $file): string
{
$adminDir = defined('__TYPECHO_ADMIN_DIR__')
? __TYPECHO_ADMIN_DIR__
: '/admin/';
return rtrim(__TYPECHO_ROOT_DIR__, '/\\') . DIRECTORY_SEPARATOR
. trim($adminDir, '/\\') . DIRECTORY_SEPARATOR
. ltrim($file, '/\\');
}然后统一通过这个函数加载后台模板:
include plugin_admin_file('header.php');
include plugin_admin_file('menu.php');
// 插件页面主体
include plugin_admin_file('copyright.php');
include plugin_admin_file('common-js.php');
include plugin_admin_file('footer.php');这段代码有几个考虑:
- 优先读取 Typecho 配置的后台目录。
- 常量不存在时回退到默认的
/admin/,兼容常规安装。 - 使用
trim()处理配置值两端可能存在的斜杠。 - 使用
DIRECTORY_SEPARATOR兼容 Linux 和 Windows 文件系统。 - 每个插件使用带自身前缀的函数名,避免多个插件在同一请求中发生全局函数重名。
本次修复分别为 FriendLinks、ZeyuAi 和 VisitAnalytics 定义了独立的后台路径函数,并替换了三个插件中共 15 处后台模板硬编码引用。
配置也必须与真实目录一致
代码支持自定义目录后,线上 config.inc.php 仍需正确配置。例如实际后台文件夹名为 custom-admin,则应设置:
define('__TYPECHO_ADMIN_DIR__', '/custom-admin/');配置值、服务器上的真实目录名以及访问后台时使用的 URL 必须一致。否则 Typecho 生成的后台链接和静态资源地址仍可能出错。
不建议通过 $_SERVER['SCRIPT_FILENAME'] 猜测后台目录。插件面板由 extending.php 转发加载,不同 Web 服务器、反向代理和部署结构下,请求路径与文件路径不一定具有稳定关系。使用 Typecho 提供的配置常量更可靠。
修复后的检查方法
先扫描插件代码,确认没有残留的硬编码后台模板路径:
rg -n -F "/admin/" usr/plugins/FriendLinks usr/plugins/ZeyuAi usr/plugins/VisitAnalytics正常情况下,只应看到路径函数中的默认回退值,不应再看到类似 include __TYPECHO_ROOT_DIR__ . '/admin/...' 的语句。
然后对修改过的 PHP 文件执行语法检查:
php -n -l usr/plugins/FriendLinks/panels/manage.php
php -n -l usr/plugins/ZeyuAi/panels/common.php
php -n -l usr/plugins/VisitAnalytics/panels/common.php部署到线上后,再完成以下验证:
- 分别打开三个插件的后台页面,确认顶部导航和页面基础样式恢复。
- 在浏览器开发者工具的 Network 面板中确认后台公共 CSS 返回
200,且 URL 使用当前后台目录。 - 检查按钮、表格和表单交互,确认后台公共 JavaScript 已成功加载。
- 清理浏览器、CDN 和 PHP OPcache 缓存,避免旧页面或旧脚本影响判断。
- 同时在默认
admin目录环境和自定义目录环境中回归测试。
小结
这类问题表面上是“线上和本地 CSS 不一致”,实际根因是插件把 Typecho 后台目录当成了固定路径。插件自身样式通过 pluginUrl 正常加载,进一步掩盖了后台公共模板包含失败的问题。
对于 Typecho 插件开发,后台目录、插件目录和站点地址都应通过框架提供的常量或 Options 属性取得,避免在代码中写死部署路径。修改后台目录可以减少默认入口暴露,但不能替代强密码、多因素认证、访问控制和及时更新等真正的安全措施。
评论
0成为第一个留下想法的人。