刚拆完第三个 Zsens Admin 插件才懂:目录结构不是"照着抄",是调试成本逼出来的
【总结】作者通过维护混乱插件后重构目录结构,强调入口文件应精简、调试分离,推荐本地PHP+SQLite方案(启动快、便携),并总结5点检查清单避免常见坑,如激活钩子路径问题等。
之前接了个二手插件的维护活,原开发者把控制器、模型、视图全塞在一个 includes/ 文件夹里,文件名还是 func1.php、func2.php 这种风格。本地改一行逻辑,调试器里断点打到怀疑人生——根本分不清哪个文件在什么时候被加载。那次之后我才正经坐下来,重新理了一套能让新手少踩坑的目录骨架。
先说我的目录结构,不是从哪个框架抄的,是被 var_dump 和 debug_backtrace 反复教育后的结果:
my-plugin/ ├── my-plugin.php # 唯一入口,只做一件事:bootstrap ├── bootstrap.php # 实际初始化:常量、自动加载、钩子注册 ├── config/ │ └── plugin.php # 版本号、表前缀、默认配置,不掺逻辑 ├── src/ │ ├── Admin/ # 后台专属:菜单、页面、Ajax 端点 │ │ ├── MenuRegistrar.php │ │ └── Controllers/ │ ├── Core/ # 前后台通用:请求封装、响应格式、工具类 │ │ ├── Router.php # 自定义路由解析,不是 WP 的 rewrite │ │ └── Validator.php │ ├── Models/ # 纯数据层,不写 SQL,只调仓库 │ └── Repositories/ # 实际查表的地方,方便 mock 测试 ├── assets/ │ ├── css/ │ ├── js/ │ └── images/ ├── languages/ ├── tests/ # 本地调试的核心阵地 │ ├── phpunit/ │ └── fixtures/ # 假数据、模拟表结构 └── vendor/ # composer 依赖,提交时 ignore
关键认知转变:入口文件必须"薄到透明"。我现在的 my-plugin.php 就 20 行出头:
所有"这个插件是什么、要干嘛"的判断,全扔
bootstrap.php。这样本地调试有个隐藏好处:我可以单独写个bootstrap-test.php,绕过 WP 的插件加载机制,直接用 PHPUnit 测 Core 层的类,不用启整个后台。说到本地调试环境,我试过三种方案,最后锁死在一种上:
方案 A:Docker + wp-env(官方方案)
适合团队协作,但启动慢,每次改代码要
npm run wp-env start,我笔记本风扇狂转。而且插件代码是通过 volume 挂载的,有时候文件权限抽风,改完不生效。方案 B:本地 LNMP + FTP 同步(我戒掉的蠢事)
就是标题里说的,改一行传一次,传完刷新,刷新完发现改错地方。最崩溃的是断点调试——Xdebug 配在本地 PHP,文件路径和服务器对不上,IDE 里断点变灰。
方案 C:本地 PHP 内置服务器 + SQLite(我现在用的)
不是跑完整 WP,而是用 wp-sqlite-db 让 WP 跑在 SQLite 上。整个环境就是一个文件夹,复制到 U 盘里能带走。启动命令就一行:
php -S localhost:8080 -t /path/to/wordpress配合一个小脚本
dev-watch.php,用inotifywait(Linux/Mac)或fswatch监听src/变动,自动清 OPCache、刷 transients。不是热重载,但刷新即生效,比 FTP 强一百倍。入口文件调试有个细节,我花了两小时才定位到:WP 的插件激活钩子
register_activation_hook只认主文件路径。如果你把初始化逻辑拆到bootstrap.php,钩子必须写在入口文件里,或者显式传__FILE__。我当初把钩子也挪到 bootstrap,结果激活时数据库表死活不建,因为 WP 找的是bootstrap.php的路径,不是插件主文件。现在我的 bootstrap 里会显式检查:
if (!defined('MY_PLUGIN_FILE')) { define('MY_PLUGIN_FILE', dirname(__DIR__) . '/my-plugin.php'); } register_activation_hook(MY_PLUGIN_FILE, [Installer::class, 'activate']);目录结构定下来后,本地调试还有个隐形收益:错误日志能直接定位到文件。以前全堆在
includes/里,报错是includes/func3.php on line 247,我得打开五个文件数行号。现在报错是src/Repositories/UserRepository.php on line 89,一眼知道是数据层的问题。最后分享一个我贴在显示器上的检查清单,每次开新插件前过一遍:
- 入口文件是否只负责
define+require?bootstrap.php里有没有混入业务逻辑?- 本地调试环境能否在 30 秒内从零启动?
- PHPUnit 能否不依赖 WP 全局变量跑通 Core 层?
- 激活/卸载钩子是否用了正确的
__FILE__引用?第五条我踩过两次,每次都想抽自己。你们本地调试是什么方案?有比 SQLite 更轻量的玩法吗?


微信客服
QQ官方交流群