从零开发一个 WordPress AI 图片生成插件,我踩了 12 个坑
一个跨 TypeScript + PHP + Python 三端的 Stable Diffusion 插件开发全记录。
之前一直计划,从零开发了一个 WordPress 插件:用户在后台输入提示词,调用自建的 Stable Diffusion API 生成图片,自动存入媒体库。听起来简单的需求,实际上跨越了三个语言、两个框架、一个 AI 推理引擎。
技术栈是这样的:
| 层级 | 技术 |
|---|---|
| 前端界面 | TypeScript + React + @wordpress/components |
| 中间层 | PHP(WordPress REST API + 设置页面 + 数据库) |
| AI 后端 | FastAPI + diffusers + CUDA |
| 部署 | 1Panel(WordPress)+ AutoDL(GPU 推理) |
项目完整跑通后,回头整理了一下踩过的坑,发现几乎每一步都有值得记录的点。这篇文章就当是一次复盘,也给要做类似跨端 AI 应用的朋友一个参考。
坑 1:Webpack 不肯打包我的 CSS
项目用的是 @wordpress/scripts,它内置了 webpack 和 sass-loader,按理说直接 npm run build 就能输出 CSS。
第一次构建完成后,build/ 目录下只有 admin.js,没有 admin.css。检查了半天 webpack 配置,一切正常。
最后发现原因简单到让人想笑:我的 admin.scss 文件没有被任何 JS 文件引用。webpack 只会打包从入口文件可达的依赖树,一个孤立的 scss 文件它根本看不见。
解决方法:在入口文件顶部加一行:
typescript
import './styles/admin.scss';
构建成功,CSS 文件输出。这个坑教会我一件事:webpack 不是魔法,它只是忠实地从入口开始追踪依赖。没被 import 的东西,它不会打包。
坑 2:TypeScript 红波浪海
VS Code 打开项目,@wordpress/element、@wordpress/components、@wordpress/api-fetch 全部飘红:
lua
Cannot find module '@wordpress/element' or its corresponding type declarations.
WordPress 的 npm 包几乎都不带 TypeScript 类型声明。社区虽然有 @types/wordpress__* 系列,但版本滞后严重,而且经常缺具体的组件类型。
与其花半天时间找类型定义,不如务实一点。在 types.ts 里加了模块声明:
typescript
declare module '@wordpress/element' {
export const createRoot: any;
export const useState: any;
export const useEffect: any;
}
然后在 tsconfig.json 里加了两行关键配置:
json
{
"compilerOptions": {
"strict": false,
"types": []
}
}
"types": [] 这个配置很关键------它阻止 TypeScript 自动引入 node_modules/@types/* 下的所有类型定义,否则 webpack 内部的 babel、tapable 等库的类型声明也会被加载进来,报一堆无关错误。
教训 :在类型生态不完善的第三方库面前,any + 模块声明是务实方案。不要花太多时间追求完美的类型覆盖,先把功能跑通再说。
坑 3:路径双重拼接,API 请求全 404
前端页面渲染正常,但所有 API 请求都返回 404。打开浏览器 Network 一看,请求地址变成了:
bash
/wp-json/wp-json/sd-plugin/v1/settings
多了一层 /wp-json/。
原因出在 @wordpress/api-fetch 上。这个库的 path 参数会自动在前面拼接 /wp-json/,而我代码里又写了一遍:
typescript
// ❌ 错误:path 参数会被自动加上 /wp-json/
apiFetch({ path: '/wp-json/sd-plugin/v1/settings' })
// ✅ 正确:用 url 参数完全控制路径
apiFetch({ url: '/wp-json/sd-plugin/v1/settings' })
教训 :读第三方库文档要关注参数的隐式行为。api-fetch 中 path 和 url 是两个行为不同的参数,这个细节文档里一笔带过,很容易忽略。
坑 4:Python 3.13 太新,AI 库集体水土不服
本地 Windows 环境装的是 Python 3.13,执行 pip install transformers 时直接报错:
vbnet
PyO3's maximum supported version (3.12)
Python 3.13 是 2024 年 10 月发布的,很多 AI 库底层用 Rust/C 写的扩展(通过 PyO3 编译),还没跟上节奏。
解决方法:用 conda 新建了一个 Python 3.10 环境:
bash
conda create -n sd python=3.10 -y
conda activate sd
教训 :做 AI 开发不要追新 Python。截至 2025 年中,Python 3.10 是 AI 生态的黄金版本,PyTorch、diffusers、transformers 等核心库的支持最完整。
坑 5:diffusers 和 transformers 版本打架
模型文件下载好了,启动服务时崩了:
csharp
'CLIPTextModel' object has no attribute 'text_model'
diffusers 和 transformers 两个库对 CLIP 模型的内部结构有不同假设,最新版不兼容。
解决方法是锁定版本:
bash
pip install transformers==4.36.0 diffusers==0.25.0
教训 :HuggingFace 生态的库更新非常快,API 破坏性变更也频繁。生产环境必须在 requirements.txt 里精确锁版本,不能用 >=。
坑 6:CUDA 驱动太老,PyTorch 不认
在 AutoDL 上租了个 RTX 2080 Ti 实例,PyTorch 装好后:
csharp
The NVIDIA driver on your system is too old (found version 12040)
torch.cuda.is_available() → False
装了 CUDA 12.1 版的 PyTorch,但实例的驱动只支持到 CUDA 12.0。
解决方法:降级到 CUDA 11.8 版本的 PyTorch:
bash
pip install torch --index-url https://download.pytorch.org/whl/cu118
| 驱动版本 | 最高支持 CUDA |
|---|---|
| 520+ | 11.8 |
| 525+ | 12.0 |
| 545+ | 12.3 |
教训 :租 GPU 实例后,先跑 nvidia-smi 看驱动版本,再决定装哪个 CUDA 版本的 PyTorch。
坑 7:pip 下载 2GB 文件要 1 小时
从 PyTorch 官网下载 torch-2.5.0-cu121,780MB,速度只有 200KB/s。
解决方法:换国内镜像:
bash
pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple
瞬间拉到 10MB/s,几十秒搞定。
教训:在任何国内服务器上做 Python 开发,配镜像源是第一步。清华源对 PyTorch 的支持最好。
坑 8:Windows 的 venv 上传到 Linux 直接废
本地打包时图方便,把整个项目文件夹(包括 venv/)压缩上传到 AutoDL。解压后执行 source venv/bin/activate,pip 直接报找不到。
venv 不是跨平台的。Windows 的激活脚本在 venv/Scripts/activate,Linux 在 venv/bin/activate,内部路径完全不同。
解决方法 :.gitignore 里加 venv/,只上传源码。到 Linux 上重建:
bash
python3 -m venv venv
source venv/bin/activate
教训:虚拟环境是环境相关的,不能跨平台复用。
坑 9:WordPress SQLite 插件踩坑
为了省事不想装 MySQL,用了 WordPress 的 SQLite 数据库插件。结果新版插件的 db.php 路径从根目录移到了 wp-includes/sqlite/,官方文档还是旧版的复制命令,导致 db.php 根本没放到正确位置。
折腾了半小时后放弃了,直接装 MySQL:
bash
apt install -y mysql-server php-mysql
mysql -e "CREATE DATABASE wordpress;"
三分钟搞定。
教训:集成测试环境可以用 SQLite 图省事,但稍微复杂一点的项目直接上 MySQL。少折腾。
坑 10:Nginx 占用 80 端口,Apache 启动失败
服务器上已经有 Nginx 了,又用脚本装了 Apache,重启时报错:
perl
(98) Address already in use: could not bind to 0.0.0.0:80
解决方法:
bash
lsof -i :80
# 发现 nginx 占着,直接用 nginx 就行
systemctl stop apache2
systemctl disable apache2
然后给 Nginx 加上 PHP 支持(PHP-FPM),不需要 Apache。
教训 :装环境前先 lsof -i :端口 检查谁在占用。
坑 11:PHP-FPM 版本不匹配,Nginx 报 502
Nginx 配置里写的:
javascript
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
但系统装的是 PHP 8.1,sock 文件叫 php8.1-fpm.sock。Nginx 连不上,直接 502。
解决方法:
bash
ls /var/run/php/ # 看实际的文件名,再改 nginx 配置
教训 :不同 Ubuntu 版本默认 PHP 版本不同。ls 确认比猜版本号靠谱。
坑 12:debug.log 不生成,排查错误全靠猜
WordPress 报 "There has been a critical error",但 wp-content/debug.log 文件不存在。wp-config.php 里 WP_DEBUG_LOG 设了 true,但就是没日志。
最后发现是 PHP 进程对 wp-content/ 目录没写权限。
解决方法:
bash
chown www-data:www-data /var/www/html/wordpress/wp-content
同时拥抱 Nginx 的错误日志:
bash
tail -f /var/log/nginx/error.log
教训 :WordPress 的 debug.log 不是银弹,Web Server 级别的错误日志更可靠。
总结:跨端 AI 项目的几条铁律
这个项目写下来,最大的感受是:跨语言全栈 AI 项目的难点不在于某个具体技术,而在于多端之间的协议对齐和环境一致性。
几条经过验证的实践原则:
| 原则 | 说明 |
|---|---|
| 先定接口,再写代码 | API 文档是前后端的契约,字段名、错误码要精确对齐 |
| 锁定所有版本 | Python 3.10 + 固定的 requirements.txt,不要用 latest |
| venv 不上传 | 每次部署重建虚拟环境 |
| 国内配镜像 | pip/npm/wget 全部切国内源,效率差 10 倍 |
| Web Server 日志优先 | WordPress debug.log 不一定靠谱,直接看 Nginx/Apache 日志 |
| 分阶段验证 | 每个模块写完立即独立测试,不要等全部写完再联调 |
项目本身不算特别复杂,但覆盖了前后端、AI、运维的完整链路,踩完这些坑之后,对"做一个能用的 AI 产品"这件事有了更具体的体感。
希望这篇记录能让你的类似项目少走一些弯路。