diff --git a/README.md b/README.md index e09a184..00e5341 100644 --- a/README.md +++ b/README.md @@ -25,11 +25,15 @@ sitemap: path: sitemap.xml template: ./sitemap_template.xml rel: false + tags: true + categories: true ``` - **path** - Sitemap path. (Default: sitemap.xml) - **template** - Custom template path. This file will be used to generate sitemap.xml (See [default template](/sitemap.xml)) - **rel** - Add [`rel-sitemap`](http://microformats.org/wiki/rel-sitemap) to the site's header. (Default: `false`) +- **tags** - Add site's tags +- **categories** - Add site's categories ## Exclude Posts/Pages diff --git a/index.js b/index.js index 6a147cb..3e99d77 100644 --- a/index.js +++ b/index.js @@ -5,7 +5,9 @@ const { extname } = require('path'); hexo.config.sitemap = Object.assign({ path: 'sitemap.xml', - rel: false + rel: false, + tags: true, + categories: true }, hexo.config.sitemap); const config = hexo.config.sitemap; diff --git a/lib/generator.js b/lib/generator.js index 78357fe..ae71a01 100644 --- a/lib/generator.js +++ b/lib/generator.js @@ -5,16 +5,18 @@ const template = require('./template'); module.exports = function(locals) { const { config } = this; + const { sitemap, skip_render } = config; + const { path, tags: tagsCfg, categories: catsCfg } = sitemap; const skipRenderList = [ '**/*.js', '**/*.css' ]; - if (Array.isArray(config.skip_render)) { - skipRenderList.push(...config.skip_render); - } else if (typeof config.skip_render === 'string') { - if (config.skip_render.length > 0) { - skipRenderList.push(config.skip_render); + if (Array.isArray(skip_render)) { + skipRenderList.push(...skip_render); + } else if (typeof skip_render === 'string') { + if (skip_render.length > 0) { + skipRenderList.push(skip_render); } } @@ -27,18 +29,21 @@ module.exports = function(locals) { }); if (posts.length <= 0) { - config.sitemap.rel = false; + sitemap.rel = false; return; } - const xml = template(config).render({ + const data = template(config).render({ config, - posts + posts, + sNow: new Date(), + tags: tagsCfg ? locals.tags.toArray() : [], + categories: catsCfg ? locals.categories.toArray() : [] }); return { - path: config.sitemap.path, - data: xml + path, + data }; }; diff --git a/lib/template.js b/lib/template.js index 41a2c56..bc0e101 100644 --- a/lib/template.js +++ b/lib/template.js @@ -18,6 +18,7 @@ module.exports = function(config) { return encodeURL(str); }); + // Extract date from datetime env.addFilter('formatDate', input => { return input.toISOString().substring(0, 10); }); diff --git a/sitemap.xml b/sitemap.xml index 9c13a14..59af8bb 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -10,4 +10,29 @@ {% endif %} </url> {% endfor %} + + <url> + <loc>{{ config.url | uriencode }}</loc> + <lastmod>{{ sNow | formatDate }}</lastmod> + <changefreq>daily</changefreq> + <priority>1.0</priority> + </url> + + {% for tag in tags %} + <url> + <loc>{{ tag.permalink | uriencode }}</loc> + <lastmod>{{ sNow | formatDate }}</lastmod> + <changefreq>daily</changefreq> + <priority>0.6</priority> + </url> + {% endfor %} + + {% for cat in categories %} + <url> + <loc>{{ cat.permalink | uriencode }}</loc> + <lastmod>{{ sNow | formatDate }}</lastmod> + <changefreq>daily</changefreq> + <priority>0.6</priority> + </url> + {% endfor %} </urlset> diff --git a/test/index.js b/test/index.js index 5c78bfa..e8f29db 100644 --- a/test/index.js +++ b/test/index.js @@ -3,8 +3,14 @@ require('chai').should(); const Hexo = require('hexo'); const cheerio = require('cheerio'); -const { encodeURL } = require('hexo-util'); +const { deepMerge, encodeURL } = require('hexo-util'); const { ready, transform } = require('camaro'); +const sitemapCfg = { + path: 'sitemap.xml', + rel: false, + tags: true, + categories: true +}; const p = async xml => { await ready(); @@ -19,9 +25,11 @@ const p = async xml => { describe('Sitemap generator', () => { const hexo = new Hexo(__dirname, {silent: true}); - hexo.config.sitemap = { - path: 'sitemap.xml' - }; + hexo.config.sitemap = sitemapCfg; + const defaultCfg = deepMerge(hexo.config, { + sitemap: sitemapCfg + }); + const Post = hexo.model('Post'); const Page = hexo.model('Page'); const generator = require('../lib/generator').bind(hexo); @@ -36,6 +44,8 @@ describe('Sitemap generator', () => { {source: 'bar', slug: 'bar', updated: 1e8 + 1}, {source: 'baz', slug: 'baz', updated: 1e8 - 1} ]); + await Promise.all(data.map(post => post.setTags(['lorem']))); + await Promise.all(data.map(post => post.setCategories(['ipsum']))); posts = data; data = await Page.insert([ {source: 'bio/index.md', path: 'bio/', updated: 1e8 - 3}, @@ -46,20 +56,67 @@ describe('Sitemap generator', () => { locals = hexo.locals.toObject(); }); + beforeEach(() => { + hexo.config = deepMerge(hexo.config, defaultCfg); + }); + it('default', async () => { const result = generator(locals); + const { items } = await p(result.data); result.path.should.eql('sitemap.xml'); result.data.should.eql(sitemapTmpl.render({ config: hexo.config, - posts: posts + posts, + sNow: new Date(), + tags: locals.tags.toArray(), + categories: locals.categories.toArray() })); - const { items } = await p(result.data); - items.forEach((element, index) => { - element.link.should.eql(posts[index].permalink); - element.date.should.eql(posts[index].updated.toISOString().substring(0, 10)); - }); + for (let i = 0; i < posts.length; i++) { + items[i].link.should.eql(posts[i].permalink); + items[i].date.should.eql(posts[i].updated.toISOString().substring(0, 10)); + } + }); + + it('tags', async () => { + const { data } = generator(locals); + const { items } = await p(data); + + const result = items.filter(({ link }) => link.includes('tags')); + + const check = result.length > 0; + check.should.eql(true); + }); + + it('tags - disable', async () => { + hexo.config.sitemap.tags = false; + const { data } = generator(locals); + const { items } = await p(data); + + const result = items.filter(({ link }) => link.includes('tags')); + + result.length.should.eql(0); + }); + + it('categories', async () => { + const { data } = generator(locals); + const { items } = await p(data); + + const result = items.filter(({ link }) => link.includes('categories')); + + const check = result.length > 0; + check.should.eql(true); + }); + + it('categories - disable', async () => { + hexo.config.sitemap.categories = false; + const { data } = generator(locals); + const { items } = await p(data); + + const result = items.filter(({ link }) => link.includes('categories')); + + result.length.should.eql(0); }); describe('skip_render', () => {