有个这样的需求:一个用 WordPress 搭建的博客,假设网站域名为 jtx8.com,想让上面的图片都使用 img.xuwei.de 这个域名。为了让问题简单化,假定两个域名的图片资源的目录结构一致,即 //jtx8.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/ 等价于 //jtx8.com/wp-content/。
其实,提出文章开头那个需求,多半就是用的 CDN。若是用了 CDN,那这一环节就不是要实现的,而是已经实现了吧,就跳过去吧。
另外还有可能就是,单纯想在自己主机/服务器上实现两个地址的等价。直接的想法是,把两个域名绑定在同一个目录;这是可以实现我们的需求的,但是也就把别的无关的网页也都涵盖进来了。事实上,我们只需要让 /wp-content/ 目录的两个地址等价就好了。一个简单的实现方法是,利用地址重写(rewrite)(这时候两个域名是绑定到了不同的地方);下面我以 Nginx 环境的 VPS 为例,说一下细节。
假设 shansing.com 的网站根目录是 /var/www/jtx8.com/
,那么 /wp-content/ 目录就可以写成 /var/www/jtx8.com/wp-content/
。则对 img.xuwei.de 的主机添加以下 rewrite 规则:
location ~ /wp-content/ {
alias /var/www/jtx8.com/wp-content/;
}
也可以这样写:
location ~ /wp-content/ {
root /var/www/jtx8.com/;
}
重载 Nginx,使规则生效。这个时候,访问 //img.xuwei.de/wp-content/ 下面的东西实际上取得的就是 //jtx8.com/wp-content/ 下面的啦。
也有别的简单的方法。比如完全把两个域名绑定在同一个目录,但是在网页里写上域名判断:如果是 img.xuwei.de 就不输出并抛出错误。
环节2:使 WordPress 自动替换域名
经过上一个环节,我们已经让两个地址等价了。于是乎,我们修改主题文件,把图片资源的域名都替换一下。而每次发文,也都要注意修改图片资源的域名。(已经存在的文章可以通过 SQL 语句批量修改。)那有没有方法不用每次发文都手动修改呢?当然有。
WordPress 提供了很多了钩子(Hook),我们可以通过添加过滤器(Filter)和动作(Action)来方便地实现不少操作。
一个思路是,利用 wp_get_attachment_url 的钩子自动替换域名,如下:
/* 自动替换媒体库图片的域名 */
function attachment_url_replace($text){
$replace = array('//jtx8.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('//jtx8.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('//jtx8.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 代码中是可以直接这样写的,协议自适应,是推荐的写法。