Zsens Admin 插件本地调试:我用"入口文件三件套"把每次改代码都手动传FTP的蠢事戒掉了

小助手
小助手 版主圣羽星庭 勋望元宿志愿先锋
社区管理
插件开发 49 浏览 0 回复

刚摸插件开发那会儿,我的 workflow 堪称原始人:改一行代码 → 打包 → 传 FTP → 刷新后台 → 白屏 → 猜错在哪 → 重复二十遍。直到我把本地环境整明白,才发现之前浪费的时间够写三个功能模块了。这篇只聊最基础的骨架:目录怎么摆、入口文件怎么写、本地怎么做到保存即生效。

一、目录结构:别一上来就摊大饼

我见过太多新手把全部文件怼在根目录,结果激活插件时加载顺序全乱。我的做法是按"生命周期"切分,让 WordPress 的加载器一眼能找到该找的:

zsens-admin/
├── zsens-admin.php          # 唯一入口,只做一件事:引导
├── bootstrap.php            # 实际初始化:常量、自动加载、容器
├── src/
│   ├── Core/                # 插件内核,不依赖具体业务
│   │   ├── Plugin.php       # 单例容器,管注册、管生命周期
│   │   └── Loader.php       # 钩子批量注册器
│   ├── Admin/               # 后台专属
│   │   ├── Menu/
│   │   ├── Pages/
│   │   └── Assets/
│   └── Frontend/            # 如果有前台部分
├── assets/                  # 构建后的静态资源
├── languages/
└── .env.local               # 本地调试开关,绝不进版本库

关键点:zsens-admin.phpbootstrap.php 分离。前者是 WordPress 的"门面",后者才是你的"里子"。这样本地调试时,我可以只换里子不动门面,避免重新激活插件。

二、入口文件:三行代码的讲究

主入口文件我控制在 50 行以内,只做三件事:

<?php
/**
 * Plugin Name: Zsens Admin
 * ...
 */

// 1. 拒绝直接访问
if (!defined('ABSPATH')) {
    exit('Cheatin\' uh?');
}

// 2. 定义基础常量(路径、URL、版本)
define('ZSENS_ADMIN_PATH', plugin_dir_path(__FILE__));
define('ZSENS_ADMIN_URL', plugin_dir_url(__FILE__));
define('ZSENS_ADMIN_VERSION', '1.0.0');

// 3. 引导启动
require_once ZSENS_ADMIN_PATH . 'bootstrap.php';

\Zsens\Admin\Core\Plugin::instance()->run();

注意第三行的 run() 不是立即执行所有逻辑,而是"注册"所有钩子。WordPress 的插件加载是多点触发的,你的 admin_initwp_enqueue_scripts 都要等到对应时机才点火。很多新手在入口文件直接跑业务代码,结果 is_admin() 还没准备好就判断环境,逻辑全乱。

三、本地调试环境:我用 Docker Compose 搭的"一键沙盘"

我的 docker-compose.yml 核心就这些:

version: '3.8'
services:
  wordpress:
    image: wordpress:6.4-php8.2-apache
    volumes:
      - ./zsens-admin:/var/www/html/wp-content/plugins/zsens-admin
      - ./debug.log:/var/www/html/wp-content/debug.log
    environment:
      WORDPRESS_DEBUG: 1
    ports:
      - "8080:80"

重点是 volumes 的绑定挂载:本地 ./zsens-admin 直接映射到容器里的插件目录。改代码保存瞬间生效,不用传 FTP,不用重启容器。

但这里有个坑:PHP 的 opcache 在 Docker 里默认开启,文件改了但缓存没刷新,你会怀疑人生。我的解法是在 bootstrap.php 里加一段"本地开发保险":

if (defined('ZSENS_LOCAL_DEV') && ZSENS_LOCAL_DEV) {
    ini_set('opcache.enable', 0);
    ini_set('opcache.revalidate_freq', 0);
}

然后在 .env.local 里定义常量,通过 wp-config.phprequire 引入。生产环境没有这个文件,自然不走这段逻辑。

四、让错误尖叫:调试器接不上的兜底方案

Xdebug 配不好的时候,我靠三样东西活命:

1. WP_DEBUG_LOG + 实时 tail:tail -f debug.log | grep ZSENS,所有我的日志带前缀过滤出来。

2. 在 bootstrap.php 里注册一个谁都没法躲的异常捕获:

set_exception_handler(function ($e) {
    if (defined('ZSENS_LOCAL_DEV')) {
        wp_die(sprintf(
            '<pre>Zsens Fatal: %s\n%s</pre>',
            $e->getMessage(),
            $e->getTraceAsString()
        ));
    }
    // 生产环境走正常日志通道
});

3. 浏览器插件"Query Monitor"看钩子执行顺序,比 var_dump 堆满屏幕清爽一百倍。

五、一个让我纠结过的细节:入口文件到底要不要做自动加载

Composer 的 autoload 很香,但 WordPress 生态里不是所有环境都有 Composer。我的妥协方案:本地开发用 Composer + PSR-4,打包发布时 composer dump-autoload -o 生成优化后的类映射,连同 vendor/autoload.php 一起进版本。入口文件里这样写:

$autoload = ZSENS_ADMIN_PATH . 'vendor/autoload.php';
if (file_exists($autoload)) {
    require_once $autoload;
} else {
    // 兜底:手动 require 核心类,保证裸环境能跑
    require_once ZSENS_ADMIN_PATH . 'src/Core/Plugin.php';
    require_once ZSENS_ADMIN_PATH . 'src/Core/Loader.php';
}

这样 GitHub 下载的 ZIP 包直接装也能用,Composer 用户享受自动加载,两头不耽误。

六、我现在保存代码后的完整流程

1. IDE 里 Ctrl+S
2. 浏览器刷新(偶尔要硬刷新清 JS 缓存)
3. 有问题 → debug.log 秒定位 / 异常捕获直接看栈
4. 没问题 → 继续写下一个功能

从原来的五分钟循环压缩到十秒以内。不是工具多高级,是目录和入口文件把"该在哪加载、该什么时候加载"理清楚了,调试器才能跟上你的思路。

你们本地调试还有什么野路子?我试过 Vagrant、Lando、DDEV,最后留在 Docker Compose 主要是因为配置够薄、够透明。如果有更轻的方案欢迎砸过来。

评论0
回复 · 0
还没有回复
微信客服 微信客服