diff --git a/core/server/helpers/ghost_head.js b/core/server/helpers/ghost_head.js index 40db4e10be..3fda5fb358 100644 --- a/core/server/helpers/ghost_head.js +++ b/core/server/helpers/ghost_head.js @@ -43,8 +43,8 @@ ghost_head = function (options) { trimmedVersion = trimmedVersion ? trimmedVersion.match(majorMinor)[0] : '?'; // Push Async calls to an array of promises ops.push(urlHelper.call(self, {hash: {absolute: true}})); - ops.push(meta_description.call(self)); - ops.push(meta_title.call(self)); + ops.push(meta_description.call(self, options)); + ops.push(meta_title.call(self, options)); if (self.post) { ops.push(imageHelper.call(self.post, {hash: {absolute:true}})); diff --git a/core/server/helpers/meta_description.js b/core/server/helpers/meta_description.js index ef89825cca..37eb363f6f 100644 --- a/core/server/helpers/meta_description.js +++ b/core/server/helpers/meta_description.js @@ -11,26 +11,26 @@ var _ = require('lodash'), filters = require('../filters'), meta_description; -meta_description = function () { - var description, - blog, - pagePattern = new RegExp('\\/page\\/'); +meta_description = function (options) { + options = options || {}; - if (_.isString(this.relativeUrl)) { - blog = config.theme; - if (!this.relativeUrl || this.relativeUrl === '/' || this.relativeUrl === '') { - description = blog.description; - } else if (this.author) { - description = pagePattern.test(this.relativeUrl) ? '' : this.author.bio; - } else if (this.tag) { - if (pagePattern.test(this.relativeUrl)) { - description = ''; - } else { - description = _.isEmpty(this.tag.meta_description) ? '' : this.tag.meta_description; - } - } else if (this.post) { - description = _.isEmpty(this.post.meta_description) ? '' : this.post.meta_description; - } + var context = options.data.root.context, + description; + + if (this.meta_description) { + description = this.meta_description; // E.g. in {{#foreach}} + } else if (_.contains(context, 'paged')) { + description = ''; + } else if (_.contains(context, 'home')) { + description = config.theme.description; + } else if (_.contains(context, 'author') && this.author) { + description = this.author.bio; + } else if (_.contains(context, 'tag') && this.tag) { + description = this.tag.meta_description; + } else if (_.contains(context, 'post') && this.post) { + description = this.post.meta_description; + } else if (_.contains(context, 'page') && this.page) { + description = this.page.meta_description; } return filters.doFilter('meta_description', description).then(function (description) { diff --git a/core/server/helpers/meta_title.js b/core/server/helpers/meta_title.js index 6ca424a2dd..eca9b0595f 100644 --- a/core/server/helpers/meta_title.js +++ b/core/server/helpers/meta_title.js @@ -14,30 +14,29 @@ var _ = require('lodash'), meta_title = function (options) { /*jshint unused:false*/ var title = '', - blog, - page, - pageString = '', - pagePattern = new RegExp('\\/' + config.routeKeywords.page + '\\/(\\d+)'); + context = options.data.root.context, + blog = config.theme, + pagination = options.data.root.pagination, + pageString = ''; - if (_.isString(this.relativeUrl)) { - blog = config.theme; - page = this.relativeUrl.match(pagePattern); - if (page) { - pageString = ' - Page ' + page[1]; - } - - if (!this.relativeUrl || this.relativeUrl === '/' || this.relativeUrl === '') { - title = blog.title; - } else if (this.author) { - title = this.author.name + pageString + ' - ' + blog.title; - } else if (this.tag) { - title = _.isEmpty(this.tag.meta_title) ? this.tag.name + pageString + ' - ' + blog.title : this.tag.meta_title; - } else if (this.post) { - title = _.isEmpty(this.post.meta_title) ? this.post.title : this.post.meta_title; - } else { - title = blog.title + pageString; - } + if (pagination && pagination.total > 1) { + pageString = ' - Page ' + pagination.page; } + + if (this.meta_title) { + title = this.meta_title; // E.g. in {{#foreach}} + } else if (_.contains(context, 'home')) { + title = blog.title; + } else if (_.contains(context, 'author') && this.author) { + title = this.author.name + pageString + ' - ' + blog.title; + } else if (_.contains(context, 'tag') && this.tag) { + title = this.tag.meta_title || this.tag.name + pageString + ' - ' + blog.title; + } else if (_.contains(context, 'post') && this.post) { + title = this.post.meta_title || this.post.title; + } else { + title = blog.title + pageString; + } + return filters.doFilter('meta_title', title).then(function (title) { title = title || ''; return title.trim(); diff --git a/core/test/unit/server_helpers/ghost_head_spec.js b/core/test/unit/server_helpers/ghost_head_spec.js index 48380965ee..7d6c7e5977 100644 --- a/core/test/unit/server_helpers/ghost_head_spec.js +++ b/core/test/unit/server_helpers/ghost_head_spec.js @@ -50,7 +50,10 @@ describe('{{ghost_head}} helper', function () { }); it('returns meta tag string', function (done) { - helpers.ghost_head.call({version: '0.3.0', post: false}).then(function (rendered) { + helpers.ghost_head.call( + {version: '0.3.0', post: false}, + {data: {root: {context: []}}} + ).then(function (rendered) { should.exist(rendered); rendered.string.should.equal('\n' + ' \n' + @@ -61,7 +64,10 @@ describe('{{ghost_head}} helper', function () { }); it('returns meta tag string even if version is invalid', function (done) { - helpers.ghost_head.call({version: '0.9'}).then(function (rendered) { + helpers.ghost_head.call( + {version: '0.9'}, + {data: {root: {context: []}}} + ).then(function (rendered) { should.exist(rendered); rendered.string.should.equal('\n' + ' \n' + @@ -88,7 +94,10 @@ describe('{{ghost_head}} helper', function () { } }; - helpers.ghost_head.call({relativeUrl: '/post/', version: '0.3.0', post: post}).then(function (rendered) { + helpers.ghost_head.call( + {relativeUrl: '/post/', version: '0.3.0', post: post}, + {data: {root: {context: ['post']}}} + ).then(function (rendered) { should.exist(rendered); rendered.string.should.equal('\n \n' + ' \n' + @@ -141,7 +150,10 @@ describe('{{ghost_head}} helper', function () { } }; - helpers.ghost_head.call({relativeUrl: '/post/', version: '0.3.0', post: post}).then(function (rendered) { + helpers.ghost_head.call( + {relativeUrl: '/post/', version: '0.3.0', post: post}, + {data: {root: {context: ['post']}}} + ).then(function (rendered) { should.exist(rendered); rendered.string.should.equal('\n \n' + ' \n' + @@ -193,7 +205,10 @@ describe('{{ghost_head}} helper', function () { } }; - helpers.ghost_head.call({relativeUrl: '/post/', version: '0.3.0', post: post}).then(function (rendered) { + helpers.ghost_head.call( + {relativeUrl: '/post/', version: '0.3.0', post: post}, + {data: {root: {context: ['post']}}} + ).then(function (rendered) { should.exist(rendered); rendered.string.should.equal('\n \n' + ' \n' + @@ -242,7 +257,10 @@ describe('{{ghost_head}} helper', function () { } }; - helpers.ghost_head.call({relativeUrl: '/post/', version: '0.3.0', post: post}).then(function (rendered) { + helpers.ghost_head.call( + {relativeUrl: '/post/', version: '0.3.0', post: post}, + {data: {root: {context: ['post']}}} + ).then(function (rendered) { should.exist(rendered); rendered.string.should.equal('\n \n' + ' \n' + @@ -296,7 +314,10 @@ describe('{{ghost_head}} helper', function () { } }; - helpers.ghost_head.call({relativeUrl: '/post/', version: '0.3.0', post: post}).then(function (rendered) { + helpers.ghost_head.call( + {relativeUrl: '/post/', version: '0.3.0', post: post}, + {data: {root: {context: ['post']}}} + ).then(function (rendered) { should.exist(rendered); rendered.string.should.equal('\n' + ' \n' + @@ -307,7 +328,10 @@ describe('{{ghost_head}} helper', function () { }); it('returns canonical URL', function (done) { - helpers.ghost_head.call({version: '0.3.0', relativeUrl: '/about/'}).then(function (rendered) { + helpers.ghost_head.call( + {version: '0.3.0', relativeUrl: '/about/'}, + {data: {root: {context: ['page']}}} + ).then(function (rendered) { should.exist(rendered); rendered.string.should.equal('\n' + ' \n' + @@ -318,7 +342,10 @@ describe('{{ghost_head}} helper', function () { }); it('returns next & prev URL correctly for middle page', function (done) { - helpers.ghost_head.call({version: '0.3.0', relativeUrl: '/page/3/', pagination: {next: '4', prev: '2'}}).then(function (rendered) { + helpers.ghost_head.call( + {version: '0.3.0', relativeUrl: '/page/3/', pagination: {next: '4', prev: '2'}}, + {data: {root: {context: ['index', 'paged'], pagination: {total: 4, page: 3, next: 4, prev: 2}}}} + ).then(function (rendered) { should.exist(rendered); rendered.string.should.equal('\n' + ' \n' + @@ -330,7 +357,10 @@ describe('{{ghost_head}} helper', function () { }); it('returns next & prev URL correctly for second page', function (done) { - helpers.ghost_head.call({version: '0.3.0', relativeUrl: '/page/2/', pagination: {next: '3', prev: '1'}}).then(function (rendered) { + helpers.ghost_head.call( + {version: '0.3.0', relativeUrl: '/page/2/', pagination: {next: '3', prev: '1'}}, + {data: {root: {context: ['index', 'paged'], pagination: {total: 3, page: 2, next: 3, prev: 1}}}} + ).then(function (rendered) { should.exist(rendered); rendered.string.should.equal('\n' + ' \n' + @@ -356,7 +386,10 @@ describe('{{ghost_head}} helper', function () { }); it('returns correct rss url with subdirectory', function (done) { - helpers.ghost_head.call({version: '0.3.0'}).then(function (rendered) { + helpers.ghost_head.call( + {version: '0.3.0'}, + {data: {root: {context: []}}} + ).then(function (rendered) { should.exist(rendered); rendered.string.should.equal('\n' + ' \n' + @@ -391,7 +424,10 @@ describe('{{ghost_head}} helper', function () { }); it('returns meta tag plus injected code', function (done) { - helpers.ghost_head.call({version: '0.3.0', post: false}).then(function (rendered) { + helpers.ghost_head.call( + {version: '0.3.0', post: false}, + {data: {root: {context: []}}} + ).then(function (rendered) { should.exist(rendered); rendered.string.should.equal('\n' + ' \n' + diff --git a/core/test/unit/server_helpers/meta_description_spec.js b/core/test/unit/server_helpers/meta_description_spec.js index 3827c3f985..8d727e74bf 100644 --- a/core/test/unit/server_helpers/meta_description_spec.js +++ b/core/test/unit/server_helpers/meta_description_spec.js @@ -27,7 +27,10 @@ describe('{{meta_description}} helper', function () { }); it('returns correct blog description', function (done) { - helpers.meta_description.call({relativeUrl: '/'}).then(function (rendered) { + helpers.meta_description.call( + {}, + {data: {root: {context: ['home', 'index']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal('Just a blogging platform.'); @@ -36,7 +39,10 @@ describe('{{meta_description}} helper', function () { }); it('returns empty description on paginated page', function (done) { - helpers.meta_description.call({relativeUrl: '/page/2/'}).then(function (rendered) { + helpers.meta_description.call( + {}, + {data: {root: {context: ['index', 'paged']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal(''); @@ -45,8 +51,10 @@ describe('{{meta_description}} helper', function () { }); it('returns empty description for a tag page', function (done) { - var tag = {relativeUrl: '/tag/rasper-red', tag: {name: 'Rasper Red'}}; - helpers.meta_description.call(tag).then(function (rendered) { + helpers.meta_description.call( + {tag: {name: 'Rasper Red'}}, + {data: {root: {context: ['tag']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal(''); @@ -55,8 +63,10 @@ describe('{{meta_description}} helper', function () { }); it('returns empty description for a paginated tag page', function (done) { - var tag = {relativeUrl: '/tag/rasper-red/page/2/', tag: {name: 'Rasper Red'}}; - helpers.meta_description.call(tag).then(function (rendered) { + helpers.meta_description.call( + {tag: {name: 'Rasper Red'}}, + {data: {root: {context: ['tag', 'paged']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal(''); @@ -65,8 +75,10 @@ describe('{{meta_description}} helper', function () { }); it('returns tag meta_description if present for a tag page', function (done) { - var tag = {relativeUrl: '/tag/rasper-red', tag: {name: 'Rasper Red', meta_description: 'Rasper is the Cool Red Casper'}}; - helpers.meta_description.call(tag).then(function (rendered) { + helpers.meta_description.call( + {tag: {name: 'Rasper Red', meta_description: 'Rasper is the Cool Red Casper'}}, + {data: {root: {context: ['tag']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal('Rasper is the Cool Red Casper'); @@ -75,8 +87,10 @@ describe('{{meta_description}} helper', function () { }); it('returns empty description on paginated tag page that has meta data', function (done) { - var tag = {relativeUrl: '/tag/rasper-red/page/2/', tag: {name: 'Rasper Red', meta_description: 'Rasper is the Cool Red Casper'}}; - helpers.meta_description.call(tag).then(function (rendered) { + helpers.meta_description.call( + {tag: {name: 'Rasper Red', meta_description: 'Rasper is the Cool Red Casper'}}, + {data: {root: {context: ['tag', 'paged']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal(''); @@ -85,8 +99,10 @@ describe('{{meta_description}} helper', function () { }); it('returns correct description for an author page', function (done) { - var author = {relativeUrl: '/author/donald', author: {bio: 'I am a Duck.'}}; - helpers.meta_description.call(author).then(function (rendered) { + helpers.meta_description.call( + {author: {bio: 'I am a Duck.'}}, + {data: {root: {context: ['author']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal('I am a Duck.'); @@ -95,8 +111,10 @@ describe('{{meta_description}} helper', function () { }); it('returns empty description for a paginated author page', function (done) { - var author = {relativeUrl: '/author/donald/page/2/', author: {name: 'Donald Duck'}}; - helpers.meta_description.call(author).then(function (rendered) { + helpers.meta_description.call( + {author: {name: 'Donald Duck'}}, + {data: {root: {context: ['author', 'paged']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal(''); @@ -105,8 +123,10 @@ describe('{{meta_description}} helper', function () { }); it('returns empty description when meta_description is not set', function (done) { - var post = {relativeUrl: '/nice-post', post: {title: 'Post Title', html: 'Very nice post indeed.'}}; - helpers.meta_description.call(post).then(function (rendered) { + helpers.meta_description.call( + {post: {title: 'Post Title', html: 'Very nice post indeed.'}}, + {data: {root: {context: ['post']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal(''); @@ -115,8 +135,22 @@ describe('{{meta_description}} helper', function () { }); it('returns meta_description on post with meta_description set', function (done) { - var post = {relativeUrl: '/nice-post', post: {title: 'Post Title', meta_description: 'Nice post about stuff.'}}; - helpers.meta_description.call(post).then(function (rendered) { + helpers.meta_description.call( + {post: {title: 'Post Title', meta_description: 'Nice post about stuff.'}}, + {data: {root: {context: ['post']}}} + ).then(function (rendered) { + should.exist(rendered); + String(rendered).should.equal('Nice post about stuff.'); + + done(); + }).catch(done); + }); + + it('returns meta_description on post when used within {{#foreach posts}}', function (done) { + helpers.meta_description.call( + {meta_description: 'Nice post about stuff.'}, + {data: {root: {context: ['home']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal('Nice post about stuff.'); diff --git a/core/test/unit/server_helpers/meta_title_spec.js b/core/test/unit/server_helpers/meta_title_spec.js index caf6a5c20a..02787eb1c3 100644 --- a/core/test/unit/server_helpers/meta_title_spec.js +++ b/core/test/unit/server_helpers/meta_title_spec.js @@ -27,7 +27,10 @@ describe('{{meta_title}} helper', function () { }); it('returns correct title for homepage', function (done) { - helpers.meta_title.call({relativeUrl: '/'}).then(function (rendered) { + helpers.meta_title.call( + {}, + {data: {root: {context: ['home']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal('Ghost'); @@ -36,7 +39,10 @@ describe('{{meta_title}} helper', function () { }); it('returns correct title for paginated page', function (done) { - helpers.meta_title.call({relativeUrl: '/page/2/'}).then(function (rendered) { + helpers.meta_title.call( + {}, + {data: {root: {context: [], pagination: {total: 2, page: 2}}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal('Ghost - Page 2'); @@ -45,8 +51,10 @@ describe('{{meta_title}} helper', function () { }); it('returns correct title for a post', function (done) { - var post = {relativeUrl: '/nice-post', post: {title: 'Post Title'}}; - helpers.meta_title.call(post).then(function (rendered) { + helpers.meta_title.call( + {post: {title: 'Post Title'}}, + {data: {root: {context: ['post']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal('Post Title'); @@ -55,8 +63,10 @@ describe('{{meta_title}} helper', function () { }); it('returns correct title for a post with meta_title set', function (done) { - var post = {relativeUrl: '/nice-post', post: {title: 'Post Title', meta_title: 'Awesome Post'}}; - helpers.meta_title.call(post).then(function (rendered) { + helpers.meta_title.call( + {post: {title: 'Post Title', meta_title: 'Awesome Post'}}, + {data: {root: {context: ['post']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal('Awesome Post'); @@ -66,7 +76,10 @@ describe('{{meta_title}} helper', function () { it('returns correct title for a tag page', function (done) { var tag = {relativeUrl: '/tag/rasper-red', tag: {name: 'Rasper Red'}}; - helpers.meta_title.call(tag).then(function (rendered) { + helpers.meta_title.call( + tag, + {data: {root: {context: ['tag']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal('Rasper Red - Ghost'); @@ -75,8 +88,10 @@ describe('{{meta_title}} helper', function () { }); it('returns correct title for a paginated tag page', function (done) { - var tag = {relativeUrl: '/tag/rasper-red/page/2/', tag: {name: 'Rasper Red'}}; - helpers.meta_title.call(tag).then(function (rendered) { + helpers.meta_title.call( + {tag: {name: 'Rasper Red'}}, + {data: {root: {context: ['tag', 'paged'], pagination: {total: 2, page: 2}}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal('Rasper Red - Page 2 - Ghost'); @@ -85,8 +100,10 @@ describe('{{meta_title}} helper', function () { }); it('uses tag meta_title to override default response on tag page', function (done) { - var tag = {relativeUrl: '/tag/rasper-red', tag: {name: 'Rasper Red', meta_title: 'Sasper Red'}}; - helpers.meta_title.call(tag).then(function (rendered) { + helpers.meta_title.call( + {tag: {name: 'Rasper Red', meta_title: 'Sasper Red'}}, + {data: {root: {context: ['tag']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal('Sasper Red'); @@ -95,8 +112,10 @@ describe('{{meta_title}} helper', function () { }); it('uses tag meta_title to override default response on paginated tag page', function (done) { - var tag = {relativeUrl: '/tag/rasper-red', tag: {name: 'Rasper Red', meta_title: 'Sasper Red'}}; - helpers.meta_title.call(tag).then(function (rendered) { + helpers.meta_title.call( + {tag: {name: 'Rasper Red', meta_title: 'Sasper Red'}}, + {data: {root: {context: ['tag']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal('Sasper Red'); @@ -105,8 +124,10 @@ describe('{{meta_title}} helper', function () { }); it('returns correct title for an author page', function (done) { - var author = {relativeUrl: '/author/donald', author: {name: 'Donald Duck'}}; - helpers.meta_title.call(author).then(function (rendered) { + helpers.meta_title.call( + {author: {name: 'Donald Duck'}}, + {data: {root: {context: ['author']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal('Donald Duck - Ghost'); @@ -115,8 +136,10 @@ describe('{{meta_title}} helper', function () { }); it('returns correct title for a paginated author page', function (done) { - var author = {relativeUrl: '/author/donald/page/2/', author: {name: 'Donald Duck'}}; - helpers.meta_title.call(author).then(function (rendered) { + helpers.meta_title.call( + {author: {name: 'Donald Duck'}}, + {data: {root: {context: ['author', 'paged'], pagination: {total: 2, page: 2}}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal('Donald Duck - Page 2 - Ghost'); @@ -125,12 +148,26 @@ describe('{{meta_title}} helper', function () { }); it('returns correctly escaped title of a post', function (done) { - var post = {relativeUrl: '/nice-escaped-post', post: {title: 'Post Title "'}}; - helpers.meta_title.call(post).then(function (rendered) { + helpers.meta_title.call( + {post: {title: 'Post Title "'}}, + {data: {root: {context: ['post']}}} + ).then(function (rendered) { should.exist(rendered); String(rendered).should.equal('Post Title "'); done(); }).catch(done); }); + + it('returns meta_title on post when used within {{#foreach posts}}', function (done) { + helpers.meta_title.call( + {meta_title: 'Awesome Post'}, + {data: {root: {context: ['home']}}} + ).then(function (rendered) { + should.exist(rendered); + String(rendered).should.equal('Awesome Post'); + + done(); + }).catch(done); + }); });