今年三月份我在hostgator买的虚拟主机到期了,衡量几番二月就从wordpress迁到了Hexo。从这三个月左右的使用来看,Hexo让我挺满意的。一方面,它简洁且容易使用;另一方面它又给予用户很大的修改空间。奇怪的是,网上几乎没有编写Hexo插件的教程,以至于最近我折腾了好久才能写出可用的插件来让Hexo生成我预期的网页效果。这篇文章记录我编写Hexo插件的方法,希望对后来者有帮助。

首先描述一下我想要做的事情。最近一直参加Leetcode上面的比赛,而且每次参加之后都会写篇文章记录自己的做法,所以主页就被这些文章占领了。我希望主页只显示最新一篇关于Leetcode的文章。同时,我希望能有一个类似主页的页面,该页面是要列出所有关于Leetcode比赛的文章。总结说一下,我要做的事情是:

(I) 让主页只显示特定文章(或者说过滤掉特定文章)。

(II) 建立一个页面只显示特定文章。

下面我分成若干小节来描述自定义插件的方法。

插件放哪里

至少有两个地方可以放。第一个地方是博客主目录下的scripts文件夹,第二个地方是当前使用主题目录下的scripts文件夹。如果scripts文件夹不存在的话,那么手动创建该文件夹即可。

用什么语言

要用Javascript,毕竟Hexo是基于nodejs的。因为我写的插件比较简单,所以每个插件只含一个js文件。这些js文件将放在scripts文件夹中。

思路是什么

Hexo提供API让我们能很方便地写插件修改Hexo的行为。因为我们现在需要的是修改Hexo生成主页的行为,所以我们需要用到Generator

按照我的理解,生成器(Generator)能让我们指定Hexo生成某路径的页面时所用的方法。比如事情(I),我们需要在生成根路径页面(对应于主页)是能过滤某些关于Leetcode的文章。对于事情(II),我们希望生成一个新的路径页面(比如leetcode/),来展示Leetcode的文章。

怎么写插件

根据上述的思路,我们现在可以很简单地写出两个插件解决事情(I)和(II)了。因为我们需要分页功能,所以我们需要hexo-pagination这个插件。

第一个插件是index.js,解决事情(I)。需要注意的是,这个插件跟hexo-generator-index冲突。因为这个插件也是在修改主页的生成行为。因此,如果我们要自定义插件来修改主页,那么就要把hexo-generator-index删除。

var pagination = require('hexo-pagination');

hexo.extend.generator.register('index', function(locals){
    var posts = locals.posts.sort('date', -1).toArray();
    var filtered_posts = [];
    var leetcode = true;
    for (var i = 0; i < posts.length; i ++) {
        var post = posts[i];
        if (post.title.indexOf("Leetcode Contest") > -1 && leetcode) {
            leetcode = false;
            filtered_posts.push(post);
        }
        if (post.title.indexOf("Leetcode Contest") == -1)
            filtered_posts.push(post);
    }
    return pagination('', filtered_posts, {
        perPage: 10,
        layout: ['index'],
        data: {
            __index: true
        }
    });
});

第二个插件是leetcode.js,解决事情(II)。这个插件会生成leetcode/页面来陈列所有关于Leetcode的文章。可以点击这里查看效果。

var pagination = require('hexo-pagination');

hexo.extend.generator.register('leetcode', function(locals){
    var posts = locals.posts.sort('date', -1).toArray();
    var filtered_posts = []
    for (var i=0; i < posts.length; i ++) {
        var post = posts[i];
        if (post.title.indexOf("Leetcode Contest") > -1)
            filtered_posts.push(post);
    }
    return pagination('leetcode', filtered_posts, {
        perPage: 10,
        layout: ['index'],
        data: {}
    });
});

最后说几句

看完这篇文章,我们知道怎么写插件修改Hexo生成页面的行为了。我想另一种常见需求是要操作文章的内容了。这里用两个有用的API:FilterTag。举个例子,代码高亮是用Tag插件实现的。