You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WordPress多站点媒体缩略图与特色图片无法显示问题求助

解决WordPress多站点子目录迁移后缩略图不显示问题

问题现象

  • 将项目站点迁移至作品集站点的子目录,搭建为WordPress多站点,已正确更新数据库URL及图片路径适配sites/数字的多站点文件夹结构,但媒体缩略图和特色图片仍无法显示
  • 媒体文件夹中可见图片,图片URL正确且可直接访问,但线上服务器缩略图调用wp-includes目录下的默认图片(示例URL:https://siteurl/ntwrktheme/wp-includes/images/media/default.png),本地开发环境则正常调用wp-content/uploads目录下的图片(示例URL:http://thentwrkthemenew.local/wp-content/uploads/2024/01/default.png)
  • 当前使用xCloud的Nginx主机,现有Nginx配置如下:
# XCLOUD CONFIG BEFORE
include xcloud-conf/meshkin.me/before/*;

# Fastcgi cache path
fastcgi_cache_path /etc/nginx/cache/meshkin.me levels=1:2 keys_zone=meshkin.me:100m inactive=60m;
# End of Fastcgi cache path
# WordPress multisite subdirectory rules.
map $uri $blogname{
    ~^/(?<blogpath>[^/]+/)files/(.*)       $blogpath ;
}

map $blogname $blogid{
    default -999;
    #Ref: https://wordpress.org/extend/plugins/nginx-helper/
    #include /var/www/wordpress/wp-content/plugins/nginx-helper/map.conf ;
}

server {
    # Ports to listen on
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;

    # Server name to listen for
    server_name meshkin.me;

    # Path to document root
    root /var/www/meshkin.me;

    

    # Paths to certificate files.
    ssl_certificate /etc/letsencrypt/live/meshkin.me/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/meshkin.me/privkey.pem;

    server_tokens off;
    add_header X-Frame-Options "";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
    # File to be used as index
    index index.php index.html;

    # XCLOUD CONFIG SERVER
    include xcloud-conf/meshkin.me/server/*;

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|woff2|mp4|ttf|ttc|rss|atom|jpg|jpeg|gif|png|ico|webp|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf|css|js)$ {
        access_log off; log_not_found off; expires max; add_header Cache-Control "public";
    }

    location ~* /\.(?!well-known/) {
        deny all;
    }

    location ~\.(ini|log|conf)$ {
        deny all;
    }

    # Deny access to any files with a .php extension in the uploads directory
    location ~* /(?:uploads|files)/.*\.php$ {
        deny all;
    }

    location = /xmlrpc.php {
        deny all;
    }

    # Overrides logs defined in nginx.conf, allows per site logs.
    access_log /var/log/nginx/meshkin.me-access.log;
    error_log /var/log/nginx/meshkin.me-error.log;
# The key to use when saving cache files, which will run through the MD5 hashing algorithm.
    fastcgi_cache_key "$scheme$request_method$host$request_uri";

    # If an error occurs when communicating with FastCGI server, return cached content.
    # Useful for serving cached content if the PHP process dies or timeouts.
    fastcgi_cache_use_stale error timeout updating invalid_header http_500;

    # Allow caching of requests which contain the following headers.
    fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

    # Show the cache status in server responses.
    add_header Fastcgi-Cache $upstream_cache_status;

    # Don't skip by default
    set $skip_cache 0;

    # POST requests and urls with a query string should always go to PHP
    if ($request_method = POST) {
        set $skip_cache 1;
    }

    if ($query_string != "") {
        set $skip_cache 1;
    }

    # Don't cache URIs containing the following segments
    if ($request_uri ~* "/wp-admin/|/wp-json/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml|/cart/|/checkout/|/my-account/") {
        set $skip_cache 1;
    }

    # Don't use the cache for logged in users or recent commenters
    if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in|edd_items_in_cart|woocommerce_items_in_cart") {
        set $skip_cache 1;
    }
    location ~ ^(/[^/]+/)?files/(.+) {
        try_files /wp-content/blogs.dir/$blogid/files/$2 /wp-includes/ms-files.php?file=$2 ;
        access_log off;     log_not_found off; expires max;
    }

    #avoid php readfile()
    location ^~ /blogs.dir {
        internal;
        alias /var/www/meshkin.me/wp-content/blogs.dir ;
        access_log off;     log_not_found off; expires max;
    }

    if (!-e $request_filename) {
        rewrite /wp-admin$ $scheme://$host$request_uri/ permanent;
        rewrite ^(/[^/]+)?(/wp-.*) $2 last;
        rewrite ^(/[^/]+)?(/.*\.php) $2 last;
    }

    location ~ \.php$ {
        try_files $uri = 404;
        fastcgi_buffer_size 128k;
        fastcgi_busy_buffers_size 256k;
        fastcgi_buffers 4 256k;

        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php8.1-fpm-u1_meshkin.sock;
        fastcgi_cache_bypass $skip_cache;
        fastcgi_no_cache $skip_cache;
        fastcgi_cache meshkin.me;
        fastcgi_cache_valid 60m;
        add_header X-Cache $upstream_cache_status;
        add_header X-Frame-Options "";
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Content-Type-Options "nosniff";
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    # Rewrite robots.txt
    rewrite ^/robots.txt$ /index.php last;

}

# Redirect http to https
server {
   listen 80;
   listen [::]:80;
   server_name meshkin.me;
   return 301 https://meshkin.me$request_uri;
}

# Redirect www to non-www ssl
server {
    listen 80;
    listen [::]:80;
    server_name www.meshkin.me;
    return 301 https://meshkin.me$request_uri;
}

# Redirect www to non-www
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name www.meshkin.me;
    # Paths to certificate files.
    ssl_certificate /etc/letsencrypt/live/meshkin.me/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/meshkin.me/privkey.pem;
    return 301 https://meshkin.me$request_uri;
}

# XCLOUD CONFIG AFTER
include xcloud-conf/meshkin.me/after/*;

问题根源

现有Nginx配置使用的是WordPress旧版多站点的blogs.dir文件结构规则,但当前采用的是WordPress 3.5+引入的wp-content/uploads/sites/[blog_id]新结构,导致请求无法正确映射到实际存储的文件路径,最终触发默认图片 fallback。

修复方案

修改Nginx配置中的多站点文件处理规则,替换旧的blogs.dir相关配置,适配新的uploads/sites结构:

1. 更新map规则

替换原有的map $uri $blogname和map $blogname $blogid为以下内容,正确匹配子站点的文件请求并映射到对应blog_id:

# WordPress multisite subdirectory rules for uploads/sites structure
map $uri $blog_id {
    ~^/[^/]+/wp-content/uploads/sites/([0-9]+)/    $1;
    default 0;
}

map $uri $blog_uri {
    ~^/([^/]+)/wp-content/uploads/sites/[0-9]+/(.*)    /wp-content/uploads/sites/$blog_id/$2;
}

2. 替换文件请求处理的location块

删除原有的以下两个块:

location ~ ^(/[^/]+/)?files/(.+) {
    try_files /wp-content/blogs.dir/$blogid/files/$2 /wp-includes/ms-files.php?file=$2 ;
    access_log off;     log_not_found off; expires max;
}

#avoid php readfile()
location ^~ /blogs.dir {
    internal;
    alias /var/www/meshkin.me/wp-content/blogs.dir ;
    access_log off;     log_not_found off; expires max;
}

添加适配新结构的location规则:

# Handle multisite uploads
location ~* ^/[^/]+/wp-content/uploads/sites/([0-9]+)/(.*)$ {
    try_files $blog_uri $uri /index.php?$args;
    access_log off;
    log_not_found off;
    expires max;
    add_header Cache-Control "public";
}

3. 验证并重启Nginx

修改完成后,执行以下命令验证配置语法是否正确:

nginx -t

如果验证通过,重启Nginx服务:

systemctl restart nginx

额外步骤(可选)

如果缩略图仍不显示,可尝试重新生成缩略图:

  1. 安装并启用Regenerate Thumbnails插件
  2. 运行插件的批量缩略图生成功能,确保所有缩略图正确生成到对应站点的uploads/sites/[blog_id]/目录下

内容的提问来源于stack exchange,提问作者COBNETCKNN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 13:30:54