Hexo RSS Feed 适配及美化

hexo-generator-feed,一款自动生成 Atom 1.0 和 RSS 2.0 Feed 的 Hexo 插件,我在使用这款插件时进行了一些改造,并且对 Feed 做了一些美化。

安装插件

npm install hexo-generator-feed --save

配置插件

在博客根目录的_config.yml 最后新增以下配置,具体含义及配置方法请参考官方文档

1
2
3
4
5
6
7
8
9
10
11
12
13
feed:
enable: true
type: atom
path: atom.xml
limit: 20
hub:
content:
content_limit: 140
content_limit_delim: ' '
order_by: -date
icon: icon.png
autodiscovery: true
template:

如果你需要同时生成 Atom 和 RSS 2.0 两种 Feed,那么 typepath 应该这样配置:

1
2
3
4
5
6
7
feed:
type:
- atom
- rss2
path:
- atom.xml
- rss2.xml

自定义 Feed 模板

如果你想修改插件生成的 Feed 内容,可以自定义模板。默认模板存放在插件项目包的根目录,也就是 node_modules/hexo-generator-feed 下面的 atom.xmlrss2.xml

  1. 将需要改造的模板文件复制到博客目录的 source 文件夹中,然后进行重命名。

建议文件名以下划线 "_“开头,比如”_custom_atom.xml",这样在 generate 博客文件时,Hexo 就不会将模板文件复制到 public 目录中。

  1. 在博客根目录的_config.yml 中修改 template 配置,填入自定义模板的路径及文件名。

如果你不止生成一个 Feed,那么你需要按照数组形式配置模板,并且保持顺序与 type 中的一致。

1
2
3
4
5
6
7
feed:
type:
- atom
- rss2
template:
- ./source/_custom_atom.xml
- ./source/_custom_rss2.xml
  1. 根据自己的需求修改自定义模板文件,我改的内容包括:日期字符串的时区转换与格式修改、文章封面图的字段修正、图片路径的处理、去除分类信息。

下面列出我的自定义模板:

_custom_atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom_style.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>{{ config.title }}</title>
{% if icon %}<icon>{{ icon }}</icon>{% endif %}
{% if config.subtitle %}<subtitle>{{ config.subtitle }}</subtitle>{% endif %}
<link href="{{ feed_url | uriencode }}" rel="self"/>
{% if config.feed.hub %}<link href="{{ config.feed.hub | uriencode }}" rel="hub"/>{% endif %}
<link href="{{ url | uriencode }}"/>
<updated>{% if posts.first().updated %}{{ posts.first().updated.toDate().toLocaleString() }}{% else %}{{ posts.first().date.toDate().toLocaleString() }}{% endif %}</updated>
<id>{{ url | uriencode }}</id>
{% if config.author %}
<author>
<name>{{ config.author }}</name>
{% if config.email %}<email>{{ config.email }}</email>{% endif %}
</author>
{% endif %}
<generator uri="https://hexo.io/">Hexo</generator>
{% for post in posts.toArray() %}
<entry>
<title>{{ post.title }}</title>
<link href="{{ post.permalink | uriencode }}"/>
<id>{{ post.permalink | uriencode }}</id>
<published>{{ post.date.toISOString() }}</published>
<updated>{% if post.updated %}{{ post.updated.toISOString() }}{% else %}{{ post.date.toISOString() }}{% endif %}</updated>
{% if config.feed.content and post.content %}
<content type="html"><![CDATA[{{ post.content | noControlChars | safe }}]]></content>
{% endif %}
{% if post.description %}
<summary type="html">{{ post.description }}</summary>
{% elif post.intro %}
<summary type="html">{{ post.intro }}</summary>
{% elif post.excerpt %}
<summary type="html">{{ post.excerpt }}</summary>
{% elif post.content %}
{% set short_content = post.content.substring(0, config.feed.content_limit) %}
{% if config.feed.content_limit_delim %}
{% set delim_pos = short_content.lastIndexOf(config.feed.content_limit_delim) %}
{% if delim_pos > -1 %}
<summary type="html">{{ short_content.substring(0, delim_pos) }}</summary>
{% else %}
<summary type="html">{{ short_content }}</summary>
{% endif %}
{% else %}
<summary type="html">{{ short_content }}</summary>
{% endif %}
{% endif %}
{% if post.cover %}
<content src="{{ post.cover | formatUrl }}" type="image"/>
{% endif %}
{% for tag in post.tags.toArray() %}
<category term="{{ tag.name }}" scheme="{{ tag.permalink }}"/>
{% endfor %}
</entry>
{% endfor %}
</feed>
_custom_rss2.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss_style.xsl"?>
<rss version="2.0"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>{{ config.title }}</title>
<link>{{ url }}</link>
{% if icon %}
<image>
<url>{{ icon }}</url>
<title>{{ config.title }}</title>
<link>{{ url }}</link>
</image>
{% endif %}
<atom:link href="{{ feed_url | uriencode }}" rel="self" type="application/rss+xml"/>
{% if config.feed.hub %}<atom:link href="{{ config.feed.hub | uriencode }}" rel="hub"/>{% endif %}
<description>{{ config.description }}</description>
<pubDate>{% if posts.first().updated %}{{ posts.first().updated.toDate().toLocaleString() }}{% else %}{{ posts.first().date.toDate().toLocaleString() }}{% endif %}</pubDate>
<generator>http://hexo.io/</generator>
{% for post in posts.toArray() %}
<item>
<title>{{ post.title }}</title>
<link>{{ post.permalink | uriencode }}</link>
<guid>{{ post.permalink | uriencode }}</guid>
<pubDate>{{ post.date.toISOString() }}</pubDate>
{% if post.description %}
<description>{{ post.description }}</description>
{% elif post.intro %}
<description>{{ post.intro }}</description>
{% elif post.excerpt %}
<description>{{ post.excerpt }}</description>
{% elif post.content %}
{% set short_content = post.content.substring(0, config.feed.content_limit) %}
{% if config.feed.content_limit_delim %}
{% set delim_pos = short_content.lastIndexOf(config.feed.content_limit_delim) %}
{% if delim_pos > -1 %}
<description>{{ short_content.substring(0, delim_pos) }}</description>
{% else %}
<description>{{ short_content }}</description>
{% endif %}
{% else %}
<description>{{ short_content }}</description>
{% endif %}
{% endif %}
{% if post.cover %}
<enclosure url="{{ post.cover | formatUrl }}" type="image"/>
{% endif %}
{% if config.feed.content and post.content %}
<content:encoded><![CDATA[{{ post.content | noControlChars | safe }}]]></content:encoded>
{% endif %}
{% for tag in post.tags.toArray() %}
<category domain="{{ url + tag.path | uriencode }}">{{ tag.name }}</category>
{% endfor %}
</item>
{% endfor %}
</channel>
</rss>

美化 RSS

我写了一版风格简约的 XSL,只需要简单两步即可应用。

  1. 在自定义模板顶部添加对应的语句来引入 xsl。
1
2
3
4
5
6
<!-- Atom -->
<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom_style.xsl"?>

<!-- RSS2 -->
<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss_style.xsl"?>

  1. atom_style.xslrss_style.xsl 文件放入博客目录的 source 文件夹中。
atom_style.xsl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom">
<xsl:output method="html" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title><xsl:value-of select="rss/channel/title"/></title>
<style>
body { font-family: sans-serif; padding: 2em; background: #f8f8f8; }
h1 { text-align: center; padding: 5px 0 20px; border-bottom: 1px dashed lightgray; color: DarkTurquoise; }
.author { text-align: center; margin: 1rem 0 1rem; }
.desc { text-align: center; margin: 1rem 0 1rem; color: gray }
.pubdate { text-align: center; margin: 1rem 0 2rem; color: gray }
.postcontainer { margin: 0 auto; max-width: 1000px; display: flex; flex-direction: column; gap: 1.5rem }
.item { padding: 1.2em 2em; background: #fff; border-radius: 10px; }
.title { font-size: 1.2em; font-weight: bold; margin-bottom: 12px }
.title a { color: DarkTurquoise; text-decoration: none; }
.title:hover a { text-decoration: underline; }
.date { font-size: 0.9em; color: gray; margin: 12px 0; }
.tags { margin: 18px 0 0; display: flex; gap: .5em }
.tags span { padding: 3px 10px; background: WhiteSmoke; border-radius: 8px; font-size: .9em; color: gray; }
</style>
</head>
<body>
<h1><xsl:value-of select="/atom:feed/atom:title"/></h1>
<p class="author">作者:<xsl:value-of select="/atom:feed/atom:author/atom:name"/></p>
<p class="desc"><xsl:value-of select="/atom:feed/atom:subtitle"/></p>
<p class="pubdate">更新时间:<xsl:value-of select="/atom:feed/atom:updated"/></p>
<div class="postcontainer">
<xsl:for-each select="/atom:feed/atom:entry">
<div class="item">
<div class="title">
<a href="{atom:link/@href}" target="_blank"><xsl:value-of select="atom:title"/></a>
</div>
<div class="date">
<xsl:value-of select="atom:published"/>
</div>
<div class="description">
<xsl:value-of select="atom:summary" disable-output-escaping="yes"/>
</div>
<div class="tags">
<xsl:for-each select="atom:category">
<span>
<xsl:value-of select="./@term" />
</span>
</xsl:for-each>
</div>
</div>
</xsl:for-each>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

rss_style.xsl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title><xsl:value-of select="rss/channel/title"/></title>
<style>
body { font-family: sans-serif; padding: 2em; background: #f8f8f8; }
h1 { text-align: center; padding: 5px 0 20px; border-bottom: 1px dashed lightgray; color: DarkTurquoise; }
.desc { text-align: center; margin: 1rem 0 1rem; color: gray }
.pubdate { text-align: center; margin: 1rem 0 2rem; color: gray }
.postcontainer { margin: 0 auto; max-width: 1000px; display: flex; flex-direction: column; gap: 1.5rem }
.item { padding: 1.2em 2em; background: #fff; border-radius: 10px; }
.title { font-size: 1.2em; font-weight: bold; margin-bottom: 12px }
.title a { color: DarkTurquoise; text-decoration: none; }
.title:hover a { text-decoration: underline; }
.date { font-size: 0.9em; color: gray; margin: 12px 0; }
.tags { margin: 18px 0 0; display: flex; gap: .5em }
.tags span { padding: 3px 10px; background: WhiteSmoke; border-radius: 8px; font-size: .9em; color: gray; }
</style>
</head>
<body>
<h1><xsl:value-of select="rss/channel/title"/></h1>
<p class="desc"><xsl:value-of select="rss/channel/description"/></p>
<p class="pubdate">更新时间:<xsl:value-of select="rss/channel/pubDate"/></p>
<div class="postcontainer">
<xsl:for-each select="rss/channel/item">
<div class="item">
<div class="title">
<a href="{link}" target="_blank"><xsl:value-of select="title"/></a>
</div>
<div class="date">
<xsl:value-of select="pubDate"/>
</div>
<div class="description">
<xsl:value-of select="description" disable-output-escaping="yes"/>
</div>
<div class="tags">
<xsl:for-each select="category">
<span>
<xsl:value-of select="." />
</span>
</xsl:for-each>
</div>
</div>
</xsl:for-each>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

示例效果如下:

Icon喜欢这篇作品的话,奖励一下我吧~
💗感谢你的喜欢与支持!
QRCode微信
QRCode支付宝
本作品由 小橘猫 于 2025-07-16 15:44:57 发布
作品地址:Hexo RSS Feed 适配及美化
除特别声明外,本站作品均采用 CC BY-NC-SA 4.0 许可协议,转载请注明来自 嗷呜星球
Logo