WordPress 自定义图片资源的域名

有个这样的需求:一个用 WordPress 搭建的博客,假设网站域名为 shansing.com,想让上面的图片都使用 img.xuwei.de 这个域名。为了让问题简单化,假定两个域名的图片资源的目录结构一致,即 //shansing.com/wp-content/uploads/2017/01/xxx.jpg//img.xuwei.de/wp-content/uploads/2017/01/xxx.jpg 是表示相同的图片。

我们知道,图片(和其他静态资源)都在 WordPress 的 /wp-content/ 目录下,不管是自己上传的,还是主题里面的。于是乎,我们只要对这个目录下手就行。

环节1:使两个域名的地址等价

首先,我们得想办法使得 //img.xuwei.de/wp-content/ 等价于 //shansing.com/wp-content/。

其实,提出文章开头那个需求,多半就是用的 CDN。若是用了 CDN,那这一环节就不是实现的,而是已经实现了吧,就跳过去吧。

另外还有可能就是,单纯想在自己主机/服务器上实现两个地址的等价。直接的想法是,把两个域名绑定在同一个目录;这是可以实现我们的需求的,但是也就把别的无关的网页也都涵盖进来了。事实上,我们只需要让 /wp-content/ 目录的两个地址等价就好了。一个简单的实现方法是,利用地址重写(rewrite)(这时候两个域名是绑定到了不同的地方);下面我以 Nginx 环境的 VPS 为例,说一下细节。

假设 shansing.com 的网站根目录是 /var/www/shansing.com/,那么 /wp-content/ 目录就可以写成 /var/www/shansing.com/wp-content/。则对 img.xuwei.de 的主机添加以下 rewrite 规则:

location ~ /wp-content/ {
    alias    /var/www/shansing.com/wp-content/;
}

也可以这样写:

location ~ /wp-content/ {
    root    /var/www/shansing.com/;
}

重载 Nginx,使规则生效。这个时候,访问 //img.xuwei.de/wp-content/ 下面的东西实际上取得的就是 //shansing.com/wp-content/ 下面的啦。

也有别的简单的方法。比如完全把两个域名绑定在同一个目录,但是在网页里写上域名判断:如果是 img.xuwei.de 就不输出并抛出错误。

环节2:使 WordPress 自动替换域名

经过上一个环节,我们已经让两个地址等价了。于是乎,我们修改主题文件,把图片资源的域名都替换一下。而每次发文,也都要注意修改图片资源的域名。(已经存在的文章可以通过 SQL 语句批量修改。)那有没有方法不用每次发文都手动修改呢?当然有。

WordPress 提供了很多了钩子(Hook),我们可以通过添加过滤器(Filter)和动作(Action)来方便地实现不少操作。

一个思路是,利用 wp_get_attachment_url 的钩子自动替换域名,如下:

/* 自动替换媒体库图片的域名 */
function attachment_url_replace($text){
    $replace = array('//shansing.com/wp-content/' => '//img.xuwei.de/wp-content/');//替换前 => 替换后
    $text = str_replace(array_keys($replace), $replace, $text);
    return $text;
}
if (is_admin()){
    add_filter('wp_get_attachment_url', 'attachment_url_replace');
}

这样,每次从媒体库选取图片,都会自动地替换域名。不过相对来讲,这样比较有破坏性。鉴于 wp_get_attachment_url() 函数被许多其他函数调用,牵一发而动全身,我不推荐这种用法。

另外一种思路则是,在输出的时候给它替换了,而文章数据本身不变。可以这样写:

/* 域名自动替换:正文、摘要、评论 */
function replace_text($text){
    $replace = array('//shansing.com/wp-content/' => '//img.xuwei.de/wp-content/');//替换前 => 替换后
    $text = str_replace(array_keys($replace), $replace, $text);
    return $text;
}
add_filter('the_content', 'replace_text'); //正文替换
add_filter('the_excerpt', 'replace_text'); //摘要替换
add_filter('comment_text', 'replace_text'); //评论替换

以上代码会自动替换正文、摘要和评论的内容。可以按需去掉某一行;比如也许不需要在评论中进行替换,就去掉最后一行。

网上很多教程可能就写到这里结束了。但是别忘了,WordPress 还有一个叫作“特色图片”的功能。所以,还需要在缩略图中进行替换。参考官方开发者资源的网友回答,代码可以写成:

/* 域名自动替换:缩略图 */
function modify_thumbnail_html($html, $post_id, $post_image_id) {
    $replace = array('//shansing.com/wp-content/' => '//img.xuwei.de/wp-content/');//替换前 => 替换后
    $html = str_replace(array_keys($replace), $replace, $html);
    return $html;
}
add_filter( 'post_thumbnail_html', 'modify_thumbnail_html');

结合上面两部分,工作就做完啦。在撰写文章的时候,不用改动图片的地址;前台要输出时自然会进行替换的啦。

注:本环节所列代码都应该加到所使用主题的 functions.php 文件中。注意不要加到函数内部了,加到外面去,应该保证在 <?php 内部。

大功告成

请允许我引用动画片《螺丝钉》里的一句:大功告成!

我在上面写的“//”都是代表“http://”或“https://”,在实际的 HTML 代码中是可以直接这样写的,协议自适应,是推荐的写法。

2017-1-1 18:31 P.S.修改文章标题,原题为“WordPress 替换图片资源的域名”。

2017-6-23 15:36 P.S.WordPress 的动静分离应该可以利用自带设置实现,参见 ZE3kr 的一篇文章

若无特别说明,本文系原创,遵循 署名-非商业性使用 3.0 (CC BY-NC 3.0) 协议,转载文章请注明来自【闪星空间】,或链接上原文地址:http://shansing.com/read/450/

10 条评论

  1. 不劳而获的海盗来了哈哈哈,转。

  2. [...]原文:https://shansing.com/read/450/[...]

  3. 不错的教程

  4. [...]原文:https://shansing.com/read/450//huangk

  5. Nicky Nicky

    我喜欢带那种特色图片输出的,而且强迫症喜欢分类的。比如Linux分类的文章,就喜欢放个企业的特色图片输出到首页及列表页,不过强迫症喜欢把这些分类图片单独放到非wp-content/upload文件夹下,而是单独放一个logo文件夹。。于是就杯具了

    1. 除了文中的方法,其实好好利用好 WP 自带的设置(忘了选项叫啥了,大概一个网站地址一个 WP 地址),也是可以的。

      1. Nicky Nicky

        不是啦!我是打算把分类图片单独在媒体库之外再输出一个文件夹。。。

发表评论»

NO SPAMS! 不要发垃圾评论哦!

表情