diff --git a/core/server/helpers/ghost_head.js b/core/server/helpers/ghost_head.js
index 43b59914b8..8bfe1ba8f3 100644
--- a/core/server/helpers/ghost_head.js
+++ b/core/server/helpers/ghost_head.js
@@ -21,21 +21,47 @@ var hbs = require('express-hbs'),
excerpt = require('./excerpt'),
tagsHelper = require('./tags'),
imageHelper = require('./image'),
+
+ labs = require('../utils/labs'),
+
blog,
ghost_head;
-function getImage(ops, context, contextObject) {
+function getClient() {
+ return labs.isSet('publicAPI').then(function (publicAPI) {
+ if (publicAPI === true) {
+ return api.clients.read({slug: 'ghost-frontend'}).then(function (client) {
+ client = client.clients[0];
+ if (client.status === 'enabled') {
+ return {
+ id: client.slug,
+ secret: client.secret
+ };
+ }
+
+ return {};
+ });
+ }
+
+ return {};
+ });
+}
+
+function writeMetaTag(property, content, type) {
+ type = type || property.substring(0, 7) === 'twitter' ? 'name' : 'property';
+ return '';
+}
+
+function getImage(props, context, contextObject) {
if (context === 'home' || context === 'author') {
contextObject.image = contextObject.cover;
}
- ops.push(imageHelper.call(contextObject, {hash: {absolute: true}}));
+ props.image = imageHelper.call(contextObject, {hash: {absolute: true}});
if (context === 'post' && contextObject.author) {
- ops.push(imageHelper.call(contextObject.author, {hash: {absolute: true}}));
+ props.author_image = imageHelper.call(contextObject.author, {hash: {absolute: true}});
}
-
- return ops;
}
function getPaginationUrls(pagination, relativeUrl, secure, head) {
@@ -84,11 +110,11 @@ function addContextMetaData(context, data, metaData) {
function initMetaData(context, data, results) {
var metaData = {
- url: results[0].value(),
- metaDescription: results[1].value() || null,
- metaTitle: results[2].value(),
- coverImage: results.length > 3 ? results[3].value() : null,
- authorImage: results.length > 4 ? results[4].value() : null,
+ url: results.url,
+ metaDescription: results.meta_description || null,
+ metaTitle: results.meta_title,
+ coverImage: results.image,
+ authorImage: results.author_image,
publishedDate: null,
modifiedDate: null,
tags: null,
@@ -97,7 +123,9 @@ function initMetaData(context, data, results) {
ogType: 'website',
keywords: null,
blog: blog,
- title: blog.title
+ title: blog.title,
+ clientId: results.client.id,
+ clientSecret: results.client.secret
};
if (!metaData.metaDescription) {
@@ -228,19 +256,17 @@ function chooseSchema(metaData, context, data) {
}
function finaliseStructuredData(structuredData, tags, head) {
- var type;
_.each(structuredData, function (content, property) {
if (property === 'article:tag') {
_.each(tags, function (tag) {
if (tag !== '') {
tag = hbs.handlebars.Utils.escapeExpression(tag.trim());
- head.push('');
+ head.push(writeMetaTag(property, tag));
}
});
head.push('');
} else if (content !== null && content !== undefined) {
- type = property.substring(0, 7) === 'twitter' ? 'name' : 'property';
- head.push('');
+ head.push(writeMetaTag(property, content));
}
});
return head;
@@ -262,21 +288,22 @@ ghost_head = function (options) {
useStructuredData = !config.isPrivacyDisabled('useStructuredData'),
head = [],
safeVersion = this.safeVersion,
- ops = [],
+ props = {},
structuredData,
schema,
title = hbs.handlebars.Utils.escapeExpression(blog.title),
context = self.context ? self.context[0] : null,
contextObject = self[context] || blog;
- // Push Async calls to an array of promises
- ops.push(urlHelper.call(self, {hash: {absolute: true}}));
- ops.push(meta_description.call(self, options));
- ops.push(meta_title.call(self, options));
- ops = getImage(ops, context, contextObject);
+ // Store Async calls in an object of named promises
+ props.url = urlHelper.call(self, {hash: {absolute: true}});
+ props.meta_description = meta_description.call(self, options);
+ props.meta_title = meta_title.call(self, options);
+ props.client = getClient();
+ getImage(props, context, contextObject);
// Resolves promises then push pushes meta data into ghost_head
- return Promise.settle(ops).then(function (results) {
+ return Promise.props(props).then(function (results) {
if (context) {
var metaData = initMetaData(context, self, results),
tags = tagsHelper.call(self.post, {hash: {autolink: 'false'}}).string.split(',');
@@ -310,7 +337,13 @@ ghost_head = function (options) {
// Formats schema script/JSONLD data and pushes to head array
finaliseSchema(schema, head);
}
+
+ if (metaData.clientId && metaData.clientSecret) {
+ head.push(writeMetaTag('ghost:client_id', metaData.clientId));
+ head.push(writeMetaTag('ghost:client_secret', metaData.clientSecret));
+ }
}
+
head.push('');
head.push('');
diff --git a/core/server/utils/labs.js b/core/server/utils/labs.js
index 3a0853b6d8..79b30f37a4 100644
--- a/core/server/utils/labs.js
+++ b/core/server/utils/labs.js
@@ -11,7 +11,15 @@ flagIsSet = function flagIsSet(flag) {
return setting.key === 'labs';
});
- labsValue = JSON.parse(labs.value);
+ if (!labs || !labs.value) {
+ return false;
+ }
+
+ try {
+ labsValue = JSON.parse(labs.value);
+ } catch (e) {
+ return false;
+ }
return !!labsValue[flag] && labsValue[flag] === true;
});
diff --git a/core/test/unit/server_helpers/ghost_head_spec.js b/core/test/unit/server_helpers/ghost_head_spec.js
index 81fc09fd1b..8c04e94141 100644
--- a/core/test/unit/server_helpers/ghost_head_spec.js
+++ b/core/test/unit/server_helpers/ghost_head_spec.js
@@ -10,14 +10,47 @@ var should = require('should'),
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers'),
- api = require('../../../server/api');
+ api = require('../../../server/api'),
+
+ labs = require('../../../server/utils/labs'),
+
+ sandbox = sinon.sandbox.create();
describe('{{ghost_head}} helper', function () {
- var sandbox;
+ var settingsReadStub;
+
before(function () {
utils.loadHelpers();
});
+ afterEach(function () {
+ sandbox.restore();
+ });
+ after(function () {
+ utils.restoreConfig();
+ });
+
+ beforeEach(function () {
+ settingsReadStub = sandbox.stub(api.settings, 'read').returns(new Promise.resolve({
+ settings: [
+ {value: ''}
+ ]
+ }));
+
+ sandbox.stub(api.clients, 'read').returns(new Promise.resolve({
+ clients: [
+ {slug: 'ghost-frontend', secret: 'a1bcde23cfe5', status: 'enabled'}
+ ]
+ }));
+
+ sandbox.stub(labs, 'isSet').returns(new Promise.resolve(true));
+ });
+
+ function expectGhostClientMeta(rendered) {
+ rendered.string.should.match(//);
+ rendered.string.should.match(//);
+ }
+
describe('without Code Injection', function () {
before(function () {
utils.overrideConfig({
@@ -30,25 +63,6 @@ describe('{{ghost_head}} helper', function () {
});
});
- after(function () {
- utils.restoreConfig();
- });
-
- beforeEach(function () {
- sandbox = sinon.sandbox.create();
- sandbox.stub(api.settings, 'read', function () {
- return Promise.resolve({
- settings: [
- {value: ''}
- ]
- });
- });
- });
-
- afterEach(function () {
- sandbox.restore();
- });
-
it('has loaded ghost_head helper', function () {
should.exist(handlebars.helpers.ghost_head);
});
@@ -59,6 +73,7 @@ describe('{{ghost_head}} helper', function () {
{data: {root: {context: ['paged', 'index']}}}
).then(function (rendered) {
should.exist(rendered);
+ expectGhostClientMeta(rendered);
rendered.string.should.match(//);
rendered.string.should.match(//);
rendered.string.should.match(//);
@@ -75,6 +90,7 @@ describe('{{ghost_head}} helper', function () {
{data: {root: {context: ['home', 'index']}}}
).then(function (rendered) {
should.exist(rendered);
+ expectGhostClientMeta(rendered);
rendered.string.should.match(//);
rendered.string.should.match(//);
rendered.string.should.match(//);
@@ -115,6 +131,7 @@ describe('{{ghost_head}} helper', function () {
{data: {root: {context: ['tag']}}}
).then(function (rendered) {
should.exist(rendered);
+ expectGhostClientMeta(rendered);
rendered.string.should.match(//);
rendered.string.should.match(//);
rendered.string.should.match(//);
@@ -156,6 +173,7 @@ describe('{{ghost_head}} helper', function () {
{data: {root: {context: ['tag']}}}
).then(function (rendered) {
should.exist(rendered);
+ expectGhostClientMeta(rendered);
rendered.string.should.match(//);
rendered.string.should.match(//);
rendered.string.should.match(//);
@@ -196,6 +214,7 @@ describe('{{ghost_head}} helper', function () {
{data: {root: {context: ['tag']}}}
).then(function (rendered) {
should.exist(rendered);
+ expectGhostClientMeta(rendered);
rendered.string.should.not.match(//);
rendered.string.should.not.match(//);
rendered.string.should.not.match(/"description":/);
@@ -217,6 +236,7 @@ describe('{{ghost_head}} helper', function () {
{data: {root: {context: ['tag']}}}
).then(function (rendered) {
should.exist(rendered);
+ expectGhostClientMeta(rendered);
rendered.string.should.match(//);
rendered.string.should.match(//);
rendered.string.should.match(//);
@@ -242,6 +262,7 @@ describe('{{ghost_head}} helper', function () {
{data: {root: {context: ['author']}}}
).then(function (rendered) {
should.exist(rendered);
+ expectGhostClientMeta(rendered);
rendered.string.should.match(//);
rendered.string.should.match(//);
rendered.string.should.match(//);
@@ -284,6 +305,7 @@ describe('{{ghost_head}} helper', function () {
{data: {root: {context: ['paged', 'author']}}}
).then(function (rendered) {
should.exist(rendered);
+ expectGhostClientMeta(rendered);
rendered.string.should.match(//);
rendered.string.should.match(//);
rendered.string.should.match(//);
@@ -335,7 +357,7 @@ describe('{{ghost_head}} helper', function () {
re4 = new RegExp('"dateModified": "' + post.updated_at);
should.exist(rendered);
-
+ expectGhostClientMeta(rendered);
rendered.string.should.match(//);
rendered.string.should.match(//);
rendered.string.should.match(//);
@@ -407,7 +429,7 @@ describe('{{ghost_head}} helper', function () {
re4 = new RegExp('"dateModified": "' + post.updated_at);
should.exist(rendered);
-
+ expectGhostClientMeta(rendered);
rendered.string.should.match(//);
rendered.string.should.match(//);
rendered.string.should.match(//);
@@ -477,7 +499,7 @@ describe('{{ghost_head}} helper', function () {
re4 = new RegExp('"dateModified": "' + post.updated_at);
should.exist(rendered);
-
+ expectGhostClientMeta(rendered);
rendered.string.should.match(//);
rendered.string.should.match(//);
rendered.string.should.match(//);
@@ -546,7 +568,7 @@ describe('{{ghost_head}} helper', function () {
re4 = new RegExp('"dateModified": "' + post.updated_at);
should.exist(rendered);
-
+ expectGhostClientMeta(rendered);
rendered.string.should.match(//);
rendered.string.should.match(//);
rendered.string.should.match(//);
@@ -593,6 +615,7 @@ describe('{{ghost_head}} helper', function () {
{data: {root: {context: ['page']}}}
).then(function (rendered) {
should.exist(rendered);
+ expectGhostClientMeta(rendered);
rendered.string.should.match(//);
rendered.string.should.match(//);
rendered.string.should.match(//);
@@ -609,6 +632,7 @@ describe('{{ghost_head}} helper', function () {
{data: {root: {context: ['index', 'paged'], pagination: {total: 4, page: 3, next: 4, prev: 2}}}}
).then(function (rendered) {
should.exist(rendered);
+ expectGhostClientMeta(rendered);
rendered.string.should.match(//);
rendered.string.should.match(//);
rendered.string.should.match(//);
@@ -627,6 +651,7 @@ describe('{{ghost_head}} helper', function () {
{data: {root: {context: ['index', 'paged'], pagination: {total: 3, page: 2, next: 3, prev: 1}}}}
).then(function (rendered) {
should.exist(rendered);
+ expectGhostClientMeta(rendered);
rendered.string.should.match(//);
rendered.string.should.match(//);
rendered.string.should.match(//);
@@ -661,6 +686,7 @@ describe('{{ghost_head}} helper', function () {
{data: {root: {context: []}}}
).then(function (rendered) {
should.exist(rendered);
+ expectGhostClientMeta(rendered);
rendered.string.should.match(//);
rendered.string.should.match(//);
rendered.string.should.match(//);
@@ -684,19 +710,6 @@ describe('{{ghost_head}} helper', function () {
useStructuredData: false
}
});
- sandbox = sinon.sandbox.create();
- sandbox.stub(api.settings, 'read', function () {
- return Promise.resolve({
- settings: [
- {value: ''}
- ]
- });
- });
- });
-
- after(function () {
- utils.restoreConfig();
- sandbox.restore();
});
it('does not return structured data', function (done) {
@@ -721,6 +734,7 @@ describe('{{ghost_head}} helper', function () {
{data: {root: {context: ['post']}}}
).then(function (rendered) {
should.exist(rendered);
+ expectGhostClientMeta(rendered);
rendered.string.should.match(//);
rendered.string.should.match(//);
rendered.string.should.match(//);
@@ -733,13 +747,10 @@ describe('{{ghost_head}} helper', function () {
});
describe('with Code Injection', function () {
- before(function () {
- sandbox = sinon.sandbox.create();
- sandbox.stub(api.settings, 'read', function () {
- return Promise.resolve({
- settings: [{value: ''}]
- });
- });
+ beforeEach(function () {
+ settingsReadStub.returns(new Promise.resolve({
+ settings: [{value: ''}]
+ }));
utils.overrideConfig({
url: 'http://testurl.com/',
@@ -751,17 +762,13 @@ describe('{{ghost_head}} helper', function () {
});
});
- after(function () {
- sandbox.restore();
- utils.restoreConfig();
- });
-
it('returns meta tag plus injected code', function (done) {
helpers.ghost_head.call(
{safeVersion: '0.3', context: ['paged', 'index'], post: false},
{data: {root: {context: []}}}
).then(function (rendered) {
should.exist(rendered);
+ expectGhostClientMeta(rendered);
rendered.string.should.match(//);
rendered.string.should.match(//);
rendered.string.should.match(//);