简体中文 / [English]


Hexo Plugin Configuration for Image Captions, Alert Blocks, Copyright Notices, etc.

This article is currently an experimental machine translation and may contain errors. If anything is unclear, please refer to the original Chinese version. I am continuously working to improve the translation.

A few years ago, I migrated my blog from WordPress and have been using the Hexo framework ever since.
To be honest, Hexo has been incredibly low-maintenance, allowing me to focus primarily on content creation. I’ve written quite a few articles over the years.
With SSG-generated static pages, I can effortlessly host my personal blog for free and with zero maintenance on platforms like Cloudflare Pages, GitHub Pages, or Vercel.

Recently, I got a sudden urge to redesign my blog’s homepage and about page, switched to the new Cactus theme, and during the migration, I ran into a few minor issues—some old, some new. This article documents the more universally applicable solutions. I won’t go into the nitty-gritty details like custom CSS tweaks based on personal taste.
Although Hexo and its themes use ejs and stylus—technologies I’m not very familiar with (I can only fix simple bugs)—Hexo’s plugin scripts are plain JavaScript, which is much easier to work with.
All Hexo plugins are simply JavaScript files placed under scripts/xxx.js in your blog’s root directory; Hexo automatically detects and loads them.

Adding Image Captions

In my previous Fluid theme, image captions were automatically displayed below each image, like this:

I had already included many such captions when writing posts, but the Cactus theme doesn’t have an option to enable this feature.

So, using Hexo’s Extension API, I wrote the following script to register a hook that runs after a post is rendered into HTML. It uses a regular expression to match img tags and appends a caption span right after.

1
2
3
4
5
6
7
hexo.extend.filter.register('after_post_render', function(data) {
var className = 'image-caption';
if (data.layout == 'post' || data.layout == 'page' || data.layout == 'about') {
data.content = data.content.replace(/(<img [^>]*alt="([^"]+)"[^>]*>)/g, '$1' + '<span style="text-align: center; display:block; color: grey;" class="' + className + '">$2</span>');
}
return data;
});

Markdown-Compatible Alert Blocks

The Fluid theme supports {% note success/info/warning... %}` and `{% endnote %} blocks to create styled alert sections like this:

Original Fluid note blockOriginal Fluid note block

However, after migrating to Cactus, this syntax caused rendering errors because Hexo doesn’t recognize these tags. Moreover, most Markdown editors simply display the raw tag text and can’t render it properly.

There are some plugins that add similar alert block effects using different syntax, but they’re not Markdown-compatible, which isn’t ideal.

After some [research](How can I create a text box for a note in markdown?), I settled on using > ℹ️ and > ⚠️. That is, I write directly in my posts: > ℹ️ This is a note, which in standard Markdown renders as a regular blockquote:

Standard Markdown renderingStandard Markdown rendering

Then, I wrote a Hexo plugin to detect such blockquotes and replace them with a more stylish version, like this:

This is a note

The full code is a bit long, but the key part uses a regular expression to match > ℹ️ and > ⚠️ in Markdown content and replaces them with styled div elements:

1
2
3
4
5
6
7
8
9
10
11
var md = require('marked').marked;

hexo.extend.filter.register('before_post_render', function(data) {
let regex = />\s?(ℹ️|⚠️)((.|\n)*?)(?=\n\n|$)/gs;
data.content = data.content.replace(regex, (match, p1, p2) => {
let content = p2.replace(/^>\s?/gm, '').trim();
let type = p1.trim() === 'ℹ️' ? 'info' : 'warning';
return `<style>${style}</style><div class="admonition ${type}">${md.parse(content)}</div>`;
});
return data;
}, 10);

This way, I get a clean visual style while maintaining full compatibility with standard Markdown.

I publish my articles under the CC BY-NC-SA 4.0 license, so I’d like to add a notice at the end of each post—plus, it’s a good spot for a donation link. Cactus doesn’t support this out of the box, but implementing it is straightforward:

1
2
3
4
5
hexo.extend.filter.register('before_post_render', function(data) {
if (data.layout != "post") return data;
data.content = data.content + '\n\n> ℹ️ This article is licensed under CC BY-NC-SA 4.0...\n\n'
return data;
}, 5);

This article is licensed under the CC BY-NC-SA 4.0 license.

Author: lyc8503, Article link: https://blog.lyc8503.net/en/post/hexo-config-plugin/
If this article was helpful or interesting to you, consider buy me a coffee¬_¬
Feel free to comment in English below o/