1. 问题背景
在网站运行过程中,发现前端“圈子”模块上传的媒体文件(图片、视频等)未按照当前系统时间归档,而是错误地存入了历史年份的目录中,具体表现如下:
| 上传场景 | 预期行为 | 实际异常行为 |
|---|---|---|
| 后台媒体库直接上传 | 存入当前年月目录(如 2026/09) | 正常 |
| 后台文章编辑器内上传 | 存入文章发布时间的年月目录 | 正常(WP原生机制) |
| 前端“圈子”上传 | 存入当前年月目录(如 2026/09) | 异常:存入旧文章发布时间目录 (如 2021/08 或 2023/XX) |
此外,该问题导致后续前端 Vue 组件在渲染列表时,因部分历史数据作者信息缺失(author is undefined)而引发 JS 崩溃,造成页面白屏
2. 根本原因
通过对 B2 主题核心文件 FileUpload.php 的源码审计,定位到问题根源在于 file_upload 方法对 WordPress 核心函数的调用方式
2.1 代码逻辑缺陷
在 FileUpload.php 第 572 - 611 行,存在以下核心调用:
$id = media_handle_upload('file', $request['post_id']);- 参数分析:
media_handle_upload是 WordPress 处理文件上传的核心函数,第二个参数$post_id用于将媒体文件关联到特定的文章 - WP 核心机制:当
$post_id有效时,WordPress 会自动查询该 ID 对应文章的post_date(发布时间),并以此作为物理文件夹的命名依据(例如:文章发布于 2021 年,图片则存入wp-content/uploads/2021/08/)
2.2 触发条件
B2 主题在前端发布“说说”时,JS 逻辑会传递一个 post_id,该 ID 往往指向一条旧记录,确认是JS 逻辑缺陷导致
- 复用草稿 ID:前端可能复用了用户多年前创建的未发布草稿 ID
- 回复旧动态:用户在回复一条 2021 年的旧说说时,上传的图片会被强制归档至 2021 年
- JS 逻辑缺陷:创建新动态时,后端未能正确生成新的 Post ID,而是默认传入了一个固定的旧 ID
2.3 连锁反应
由于物理路径错乱,导致数据库 _wp_attached_file 记录的路径与实际存放位置在逻辑上产生偏差。同时,部分历史圈子的 post_author 指向了已注销的用户,导致 API 返回的 JSON 数据中 author 字段为空,最终引发前端 circle.js 的 TypeError
3. 解决方案
为彻底解决此问题,采取了 “源头拦截” 与 “数据清洗”
方案一:源头拦截
目标:强制前端上传始终使用当前系统时间生成目录,无视传入的 post_id 时间
实施步骤:
修改 FileUpload.php 中的 file_upload 方法,在执行 media_handle_upload 前临时挂载 upload_dir 过滤器
// 核心修复代码
$force_current_dir = function($uploads) {
$time = current_time('mysql');
$y = substr($time, 0, 4);
$m = substr($time, 5, 2);
$subdir = "/{$y}/{$m}";
$uploads['subdir'] = $subdir;
$uploads['path'] = $uploads['basedir'] . $subdir;
$uploads['url'] = $uploads['baseurl'] . $subdir;
return $uploads;
};
add_filter('upload_dir', $force_current_dir);
$id = media_handle_upload('file', $request['post_id']);
remove_filter('upload_dir', $force_current_dir);
效果:该修改仅对 B2 前端上传接口生效,不影响后台及其他插件逻辑,确保新上传图片 100% 存入正确年月目录
方案二:历史数据清洗
目标:将已错位的历史图片从旧目录迁移至正确目录,并同步更新数据库
实施步骤:
- 编写自动化 PHP 脚本,遍历所有附件
- 对比附件的
post_date与_wp_attached_file中的路径年月 - 若不一致,自动执行物理文件移动(含缩略图)及数据库
guid和meta_value更新 - 针对个别物理文件丢失的情况,通过全局搜索定位并手动修正 SQL 记录
方案三:前端容错与缓存清理
目标:解决因作者信息缺失导致的 JS 崩溃及缓存残留问题
实施步骤:
- SQL 清洗:执行
UPDATE wp_posts SET post_author = 1 WHERE post_author NOT IN (SELECT ID FROM wp_users),将所有无主内容转移给管理员 - API 兜底:在
functions.php中添加rest_post_dispatch钩子,为缺失author的数据注入默认对象,防止前端 Vue 渲染崩溃 - 全链路清缓存:依次清理 Redis 对象缓存、CDN 静态资源缓存及浏览器本地缓存,确保新数据即时生效
4. 验证结果
| 测试项 | 测试结果 | 备注 |
|---|---|---|
| 新图片上传路径 | 正确 | 均存入 2026/09 目录 |
| 历史图片显示 | 正常 | 路径已修正,缩略图完整 |
| 前端列表加载 | 正常 | 不再报 author is undefined 错误 |
| 后台功能影响 | 无影响 | 后台媒体库上传逻辑保持原生状态 |

