Hexo修改永久链接格式并向后兼容

最近一直想简化每篇博客的永久链接,现在的永久链接大概长这样:

/2021/03/21/migrateopsmanager.en/

希望能把中间的日期去掉,变成这样:

/migrateopsmanager.en/

原因在于短链接更作为标识更为合理,而URL上带有日期字符串并没有实际的用处,除非重名的博客太多。但这不可能发生,因为所有博客都写在source/_post文件夹,博客重名会引起文件名冲突。

修改永久链接的问题

修改永久链接格式是很容易的,参考官方文档,只需要修改_config.yml,默认格式是:year/:month/:day/:title/,改成:title/即可。但修改格式会导致所有博客的永久链接变化,老格式的链接会失效,那么就会引起网站排名下滑,造成不必要的损失。

Hexo不像WordPress,做一个301跳转很容易,之前就踩过这样的坑: # 迁移Hexo博客到GitHub Pages。于是想到几种方案:

  • <head>中增加一个canonical link标签,但并不是在http层的跳转,还是有可能影响排名
  • 生成两个永久链接,让老的链接格式采用第一种方案跳转到新链接
  • 不动老链接,新写的博客使用新链接格式

思考再三,决定采用最后一种方案,比较保险。那如何实现对于新写的博客生成不同格式的永久链接?

实现新博客,新链接格式

实现思路很简单,以某个时间点为界,在这个时间点之后的博客在生成永久链接时都采用新格式。之前 # Hexo添加自定义分类菜单项并定制页面布局的实现就不大好,直接修改了Hexo源代码,导致每次升级Hexo非常痛苦。对于这么个小需求,可以通过扩展Hexo的方式实现: 写一个特殊的filter。

此前我也从来没有写过Hexo扩展,简单看了下文档,Hexo扩展就是插入一段自己的代码来修改特定的数据。对于我们的需求,filter可以完美解决这个问题:https://hexo.io/api/filter。

所谓filter,有点pipeline的意思:

Hexo passes data to filters in sequence and the filters then modify the data one after the other.

The first argument passed into each filter is data. The data passed into the next filter can be modified by returning a new value. If nothing is returned, the data remains unmodified.

读读文档发现众多filter中,有一个叫做 # post-permalink,是用来决定博客的永久链接的:

hexo.extend.filter.register('post_permalink', function(data){  
 // ...  
});

文档中有一点解释的不太清楚,就是不同的filter的输入参数是不同的,而对于不同filter的输入参数并没有详细的解释,可能需要看一下源码才能比较清楚。针对这个函数,data就是永久链接string本身,如:2021/03/21/migrateopsmanager.en/

扩展Hexo有两种方式,要么在根目录直接建一个scripts/文件夹,直接放js文件;要么写plugin。后者实现起来更麻烦一些,我们这里就采用比较简单的方式,在博客目录建scripts/文件夹,并实现一个refinepermalink.js:

var new_format_date = new Date('2021-05-01');

hexo.extend.filter.register('post_permalink', function(original_link){
    var pivot = original_link.slice(0, -1).lastIndexOf("/")
    var date_str = original_link.substring(0, pivot);
    var date = new Date(date_str);
    var title = original_link.substring(pivot + 1);

    var result = original_link;
    if (date > new_format_date)
    {
        result = title;
        console.log(' ', date, '### Change permalink:', original_link, '-->', result);
    }
    return result;
});

代码非常简单,不再解释。实现后执行hexo g即可看到效果:

$ hexo g
INFO  Start processing
  2021-06-14T16:00:00.000Z ### Change permalink: 2021/06/15/changepermalinkformat/ --> changepermalinkformat/
  2021-05-01T16:00:00.000Z ### Change permalink: 2021/05/02/sqlservercleanupqueries/ --> sqlservercleanupqueries/
  2021-05-01T16:00:00.000Z ### Change permalink: 2021/05/02/sqlservercleanupqueries.en/ --> sqlservercleanupqueries.en/
INFO  Files loaded in 1.99 s
...

References

# 玩转Hexo的Scripts

# Getting started with Hexo Plug-ins, and scripts

# Redirecting Old Permalinks on Statically Generated Blogs