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,那么 type
和 path
应该这样配置:
1 2 3 4 5 6 7
| feed: type: - atom - rss2 path: - atom.xml - rss2.xml
|
自定义 Feed 模板
如果你想修改插件生成的 Feed 内容,可以自定义模板。默认模板存放在插件项目包的根目录,也就是 node_modules/hexo-generator-feed
下面的 atom.xml
和 rss2.xml
。
- 将需要改造的模板文件复制到博客目录的
source
文件夹中,然后进行重命名。
建议文件名以下划线 "_“开头,比如”_custom_atom.xml",这样在 generate 博客文件时,Hexo 就不会将模板文件复制到 public 目录中。
- 在博客根目录的
_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
|
- 根据自己的需求修改自定义模板文件,我改的内容包括:日期字符串的时区转换与格式修改、文章封面图的字段修正、图片路径的处理、去除分类信息。
下面列出我的自定义模板:
_custom_atom.xml1 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.xml1 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>
|
我写了一版风格简约的 XSL,只需要简单两步即可应用。
- 在自定义模板顶部添加对应的语句来引入 xsl。
1 2 3 4 5 6
| <?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom_style.xsl"?>
<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss_style.xsl"?>
|
- 将
atom_style.xsl
和 rss_style.xsl
文件放入博客目录的 source
文件夹中。
atom_style.xsl1 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.xsl1 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>
|
示例效果如下:
本作品由 小橘猫 于 2025-07-16 15:44:57 发布
除特别声明外,本站作品均采用
CC BY-NC-SA 4.0 许可协议,转载请注明来自
嗷呜星球