diff --git a/lib/hexo/index.js b/lib/hexo/index.js index a14819b257..41d9ffa50b 100644 --- a/lib/hexo/index.js +++ b/lib/hexo/index.js @@ -200,15 +200,9 @@ class Hexo extends EventEmitter { return db.model('Page').find(query); }); - locals.set('categories', () => { - // Ignore categories with zero posts - return db.model('Category').filter(category => category.length); - }); + locals.set('categories', () => db.model('Category')); - locals.set('tags', () => { - // Ignore tags with zero posts - return db.model('Tag').filter(tag => tag.length); - }); + locals.set('tags', () => db.model('Tag')); locals.set('data', () => { const obj = {}; diff --git a/lib/models/category.js b/lib/models/category.js index 2da88d37f8..5c535799a6 100644 --- a/lib/models/category.js +++ b/lib/models/category.js @@ -52,7 +52,9 @@ module.exports = ctx => { }); Category.virtual('length').get(function() { - return this.posts.length; + const PostCategory = ctx.model('PostCategory'); + + return PostCategory.find({category_id: this._id}).length; }); // Check whether a category exists diff --git a/lib/models/post.js b/lib/models/post.js index 4f8eff6843..4cb28421e3 100644 --- a/lib/models/post.js +++ b/lib/models/post.js @@ -71,7 +71,17 @@ module.exports = ctx => { return Tag.find({_id: {$in: ids}}); }); + Post.method('notPublished', function() { + // The same condition as ctx._bindLocals + return (!ctx.config.future && this.date > Date.now()) || (!ctx._showDrafts() && this.published === false); + }); + Post.method('setTags', function(tags) { + if (this.notPublished()) { + // Ignore tags of draft posts + // If the post is unpublished then the tag needs to be removed, thus the function cannot be returned early here + tags = []; + } tags = removeEmptyTag(tags); const PostTag = ctx.model('PostTag'); @@ -119,6 +129,9 @@ module.exports = ctx => { }); Post.method('setCategories', function(cats) { + if (this.notPublished()) { + cats = []; + } // Remove empty categories, preserving hierarchies cats = cats.filter(cat => { return Array.isArray(cat) || (cat != null && cat !== ''); diff --git a/lib/models/tag.js b/lib/models/tag.js index 807836d73f..7f6245c861 100644 --- a/lib/models/tag.js +++ b/lib/models/tag.js @@ -43,7 +43,11 @@ module.exports = ctx => { }); Tag.virtual('length').get(function() { - return this.posts.length; + // Note: this.posts.length is also working + // But it's slow because `find` has to iterate over all posts + const PostTag = ctx.model('PostTag'); + + return PostTag.find({tag_id: this._id}).length; }); // Check whether a tag exists diff --git a/lib/plugins/helper/list_categories.js b/lib/plugins/helper/list_categories.js index 182ca4ed5d..51455f2294 100644 --- a/lib/plugins/helper/list_categories.js +++ b/lib/plugins/helper/list_categories.js @@ -29,7 +29,7 @@ function listCategoriesHelper(categories, options) { query.parent = {$exists: false}; } - return categories.find(query).sort(orderby, order).filter(cat => cat.length); + return categories.find(query).sort(orderby, order); }; const hierarchicalList = (level, parent) => { diff --git a/lib/plugins/helper/list_tags.js b/lib/plugins/helper/list_tags.js index f9970f6c0b..c75626f720 100644 --- a/lib/plugins/helper/list_tags.js +++ b/lib/plugins/helper/list_tags.js @@ -47,9 +47,6 @@ function listTagsHelper(tags, options) { // Sort the tags tags = tags.sort(orderby, order); - // Ignore tags with zero posts - tags = tags.filter(tag => tag.length); - // Limit the number of tags if (options.amount) tags = tags.limit(options.amount); diff --git a/test/scripts/models/category.js b/test/scripts/models/category.js index c48198674d..96553e68ca 100644 --- a/test/scripts/models/category.js +++ b/test/scripts/models/category.js @@ -191,6 +191,8 @@ describe('Category', () => { // draft on hexo.config.render_drafts = true; + + await Promise.all(posts.map(post => post.setCategories(['foo']))); hexo.locals.invalidate(); cat = Category.findOne({name: 'foo'}); cat.posts.map(mapper).should.eql(posts.map(mapper)); @@ -227,6 +229,8 @@ describe('Category', () => { // future off hexo.config.future = false; + + await Promise.all(posts.map(post => post.setCategories(['foo']))); hexo.locals.invalidate(); cat = Category.findOne({name: 'foo'}); cat.posts.eq(0)._id.should.eql(posts[0]._id); diff --git a/test/scripts/models/tag.js b/test/scripts/models/tag.js index 871f766082..5e77692da5 100644 --- a/test/scripts/models/tag.js +++ b/test/scripts/models/tag.js @@ -172,6 +172,7 @@ describe('Tag', () => { // draft on hexo.config.render_drafts = true; + await Promise.all(posts.map(post => post.setTags(['foo']))); tag = Tag.findOne({name: 'foo'}); hexo.locals.invalidate(); tag.posts.map(mapper).should.eql(posts.map(mapper)); @@ -206,6 +207,7 @@ describe('Tag', () => { // future off hexo.config.future = false; + await Promise.all(posts.map(post => post.setTags(['foo']))); hexo.locals.invalidate(); tag = Tag.findOne({name: 'foo'}); tag.posts.eq(0)._id.should.eql(posts[0]._id);