搜索全站
数据库 11 分钟阅读

WordPress 媒体库按月归档目录缺失修复:uploads 结构与路径重建

迁移或手工拷贝后,uploads 目录结构不对会导致图片 404。本文讲清 WordPress 的 uploads 目录组织规则、_wp_attached_file 与物理路径的对应关系、如何批量核对并修复路径不一致、目录权限与属主修正,以及关闭按月归档时的处理。

U
UFO_PF 2019-05-30 · 阅读 11 分钟
Wo 数据库
阅读提示
本文约 4,014 字,预计阅读 11 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:数据库里有记录,文件也在,但图片就是打不开

迁移后最常见的图片问题:媒体库里能看到图片缩略图(或看到裂图),前台所有图片 404。

这种情况通常是物理文件位置与数据库记录不一致——数据库说图片在 2026/10/xxx.jpg,实际文件却在 uploads/xxx.jpg 或 uploads/sites/2/2026/10/xxx.jpg。

原理分析:WordPress 的文件组织规则

目录结构

wp-content/uploads/
├── 2026/
│   ├── 01/
│   ├── 02/
│   └── 10/
│       ├── photo.jpg
│       ├── photo-150x150.jpg     缩略图
│       └── photo-300x200.jpg
└── sites/2/2026/10/            多站点子站

是否按年月分目录由后台”设置 → 媒体 → 将上传文件按年月目录组织”控制,也可以用常量:

define('UPLOADS', 'wp-content/uploads');   // 相对 ABSPATH

数据库记录

每个附件在 wp_posts 里是一条 post_type=attachment 的记录,其物理路径存在 wp_postmeta:

_wp_attached_file     = "2026/10/photo.jpg"      ← 相对 uploads 的路径
_wp_attachment_metadata = 序列化数组(含各尺寸文件名与宽高)
guid                  = "https://site.com/wp-content/uploads/2026/10/photo.jpg"

所以完整的图片 URL = uploads 的 baseurl + _wp_attached_file 的值。

两边对不上就会 404。

保姆级实操

第一步:确认当前配置

wp option get upload_path
wp option get upload_url_path
wp eval 'print_r(wp_upload_dir());'

输出里的 basedir(物理路径)与 baseurl(访问 URL)是判断依据。

第二步:核对数据库记录与实际文件

SELECT p.ID, p.post_title, m.meta_value
FROM wp_posts p
JOIN wp_postmeta m ON p.ID = m.post_id
WHERE p.post_type='attachment'
  AND m.meta_key='_wp_attached_file'
LIMIT 20;

然后到服务器上看文件是否真的在那个位置:

ls -la /var/www/site/wp-content/uploads/2026/10/ | head

第三步:批量核对脚本

#!/usr/bin/env bash
# check-uploads.sh <站点目录>
SITE="${1:?用法: $0 <站点目录>}"
UPLOADS="$SITE/wp-content/uploads"

mysql -N -e "SELECT meta_value FROM wp_postmeta WHERE meta_key='_wp_attached_file';" wordpress | while read -r f; do
  if [ ! -f "$UPLOADS/$f" ]; then
    echo "缺失: $f"
  fi
done | head -50

第四步:修复路径不一致(三种情况)

情况 A:文件都在,只是目录层级错了

比如文件实际在 uploads/2026/10/ 但数据库记录是 sites/2/2026/10/:

wp search-replace 'sites/2/' '' --include-columns=_wp_attached_file --dry-run
wp search-replace 'sites/2/' '' wp_postmeta --precise

注意限定表,避免误伤其它数据。

情况 B:文件被平铺在 uploads 根目录

需要从 guid 或文件名推断原路径,批量移动:

cd /var/www/site/wp-content/uploads
# 按文件修改时间归档(示例)
for f in *.jpg; do
  Y=$(date -r "$f" +%Y)
  M=$(date -r "$f" +%m)
  mkdir -p "$Y/$M"
  mv "$f" "$Y/$M/"
done

然后更新数据库记录:

-- 谨慎执行,先 SELECT 验证
UPDATE wp_postmeta pm
JOIN wp_posts p ON p.ID = pm.post_id
SET pm.meta_value = CONCAT('2026/10/', SUBSTRING_INDEX(pm.meta_value, '/', -1))
WHERE pm.meta_key = '_wp_attached_file'
  AND pm.meta_value NOT LIKE '%/%';

情况 C:文件根本没拷过来

从备份或旧服务器同步:

rsync -avP root@old-server:/var/www/site/wp-content/uploads/ \
  /var/www/site/wp-content/uploads/
chown -R www-data:www-data /var/www/site/wp-content/uploads

第五步:重建缩略图

文件到位但尺寸文件缺失(-150x150.jpg 之类):

wp media regenerate --yes

只重建缺失的:

wp media regenerate --only-missing --yes

第六步:修正权限与属主

find /var/www/site/wp-content/uploads -type d -exec chmod 755 {} \;
find /var/www/site/wp-content/uploads -type f -exec chmod 644 {} \;
chown -R www-data:www-data /var/www/site/wp-content/uploads

第七步:修正 URL(域名变了的情况)

wp search-replace 'https://old.com/wp-content/uploads' \
  'https://new.com/wp-content/uploads' \
  --all-tables --precise --skip-columns=guid

第八步:验证

# 抽查几张图
wp eval '
$q = new WP_Query(["post_type"=>"attachment","posts_per_page"=>5]);
foreach($q->posts as $p){ echo wp_get_attachment_url($p->ID), PHP_EOL; }
'
curl -I "$(上一步输出的某个 URL)"

应返回 200。

常见踩坑与失败案例

  1. 关闭了”按年月组织”后旧图片 404 —— 这个设置只影响新上传,已有文件的路径不会变。关闭后旧记录仍然指向 2026/10/,不要手工改旧记录。
  2. 案例:某站迁移时只拷了 uploads/2026/ 而漏了 uploads/2025/,结果 2025 年的图片全部 404。用上面的核对脚本能一次性列出所有缺失文件。
  3. _wp_attachment_metadata 与 _wp_attached_file 不一致 —— 前者是序列化数组,直接 SQL 替换会破坏。用 WP-CLI 的 search-replace(会重算序列化)而不是 SQL。
  4. 多站点路径含 sites/2 —— 拆分为单站后必须去掉 sites/2/ 前缀,否则全部裂图。
  5. Windows 迁移到 Linux 路径分隔符 —— 记录里可能有反斜杠,需要替换。
  6. 对象存储插件路径 —— 用了 OSS/COS 插件后,实际文件在云端,本地可能没有文件,这时”缺失”是正常的,不要盲目修复。

总结

媒体库路径问题的排查顺序是:确认 uploads 的 basedir/baseurl → 核对数据库记录与实际文件 → 判断是路径不一致还是文件缺失 → 同步文件 / 修正记录 → 重建缩略图 → 修正权限 → curl 验证。核心记忆点是那个公式:图片 URL = uploads baseurl + _wp_attached_file,两边任何一处对不上都会 404。改记录时务必用 WP-CLI 的 search-replace(保护序列化数据),别直接用 SQL REPLACE。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。