2019-08-19 14:41:09 +03:00
|
|
|
/* eslint-disable no-regex-spaces */
|
2020-04-29 18:44:27 +03:00
|
|
|
const should = require('should');
|
|
|
|
|
|
|
|
const sinon = require('sinon');
|
|
|
|
const _ = require('lodash');
|
|
|
|
const moment = require('moment');
|
|
|
|
const testUtils = require('../../utils');
|
|
|
|
const testUrlUtils = require('../../utils/urlUtils');
|
|
|
|
const configUtils = require('../../utils/configUtils');
|
|
|
|
const themes = require('../../../core/frontend/services/themes');
|
|
|
|
const models = require('../../../core/server/models');
|
|
|
|
const imageLib = require('../../../core/server/lib/image');
|
|
|
|
const routing = require('../../../core/frontend/services/routing');
|
|
|
|
const urlService = require('../../../core/frontend/services/url');
|
|
|
|
const helpers = require('../../../core/frontend/helpers');
|
|
|
|
const proxy = require('../../../core/frontend/services/proxy');
|
|
|
|
const settingsCache = proxy.settingsCache;
|
2014-10-10 18:54:07 +04:00
|
|
|
|
|
|
|
describe('{{ghost_head}} helper', function () {
|
2020-04-29 18:44:27 +03:00
|
|
|
let posts = [];
|
|
|
|
let tags = [];
|
|
|
|
let authors = [];
|
|
|
|
let users = [];
|
2018-12-27 17:45:36 +03:00
|
|
|
|
|
|
|
const makeFixtures = () => {
|
|
|
|
const {createPost, createUser, createTag} = testUtils.DataGenerator.forKnex;
|
|
|
|
|
|
|
|
/** TAGS - used for tag pages */
|
|
|
|
tags.push(createTag({
|
|
|
|
meta_description: 'tag meta description',
|
|
|
|
name: 'tagtitle',
|
|
|
|
meta_title: 'tag meta title',
|
|
|
|
feature_image: '/content/images/tag-image.png'
|
|
|
|
}));
|
|
|
|
|
|
|
|
tags.push(createTag({
|
|
|
|
meta_description: '',
|
|
|
|
description: 'tag description',
|
|
|
|
name: 'tagtitle',
|
|
|
|
meta_title: '',
|
|
|
|
feature_image: '/content/images/tag-image.png'
|
|
|
|
}));
|
|
|
|
tags.push(createTag({
|
2019-11-21 16:08:00 +03:00
|
|
|
description: '',
|
2018-12-27 17:45:36 +03:00
|
|
|
meta_description: '',
|
|
|
|
name: 'tagtitle',
|
|
|
|
meta_title: '',
|
|
|
|
feature_image: '/content/images/tag-image.png'
|
|
|
|
}));
|
|
|
|
|
|
|
|
tags.push(createTag({
|
|
|
|
meta_description: 'tag meta description',
|
|
|
|
title: 'tagtitle',
|
|
|
|
meta_title: 'tag meta title',
|
|
|
|
feature_image: '/content/images/tag-image.png'
|
|
|
|
}));
|
|
|
|
|
|
|
|
/** USERS - used for author PAGES */
|
|
|
|
users.push(createUser({
|
|
|
|
name: 'Author name',
|
|
|
|
slug: 'AuthorName',
|
|
|
|
bio: 'Author bio',
|
|
|
|
profile_image: '/content/images/test-author-image.png',
|
|
|
|
cover_image: '/content/images/author-cover-image.png',
|
|
|
|
website: 'http://authorwebsite.com',
|
|
|
|
facebook: 'testuser',
|
|
|
|
twitter: '@testuser'
|
|
|
|
}));
|
|
|
|
|
|
|
|
users.push(createUser({
|
|
|
|
name: 'Author name',
|
|
|
|
slug: 'AuthorName1',
|
|
|
|
bio: 'Author bio',
|
|
|
|
profile_image: '/content/images/test-author-image.png',
|
|
|
|
cover_image: '/content/images/author-cover-image.png',
|
|
|
|
website: 'http://authorwebsite.com'
|
|
|
|
}));
|
|
|
|
|
|
|
|
/** AUTHORS - related to posts */
|
2019-07-05 14:40:43 +03:00
|
|
|
authors.push(createUser({// Author 0
|
2018-12-27 17:45:36 +03:00
|
|
|
profile_image: '/content/images/test-author-image.png',
|
|
|
|
website: 'http://authorwebsite.com',
|
|
|
|
facebook: 'testuser',
|
2019-07-05 14:40:43 +03:00
|
|
|
twitter: '@testuser'
|
2018-12-27 17:45:36 +03:00
|
|
|
}));
|
|
|
|
|
2019-07-05 14:40:43 +03:00
|
|
|
authors.push(createUser({// Author 1
|
2018-12-27 17:45:36 +03:00
|
|
|
name: 'Author name',
|
|
|
|
slug: 'author2',
|
|
|
|
profile_image: '/content/images/test-author-image.png',
|
|
|
|
website: 'http://authorwebsite.com',
|
|
|
|
bio: 'Author bio',
|
|
|
|
facebook: 'testuser',
|
|
|
|
twitter: '@testuser'
|
|
|
|
}));
|
|
|
|
|
2019-07-05 14:40:43 +03:00
|
|
|
authors.push(createUser({// Author 2
|
2018-12-27 17:45:36 +03:00
|
|
|
name: 'Author name',
|
|
|
|
slug: 'author3',
|
|
|
|
profile_image: '/content/images/test-author-image.png',
|
|
|
|
website: 'http://authorwebsite.com',
|
|
|
|
facebook: 'testuser',
|
|
|
|
twitter: '@testuser',
|
|
|
|
bio: 'Author bio'
|
|
|
|
}));
|
|
|
|
|
2019-07-05 14:40:43 +03:00
|
|
|
authors.push(createUser({// Author 3
|
2018-12-27 17:45:36 +03:00
|
|
|
name: 'Author name',
|
|
|
|
url: 'http://testauthorurl.com',
|
|
|
|
slug: 'author4',
|
|
|
|
profile_image: '/content/images/test-author-image.png',
|
|
|
|
website: 'http://authorwebsite.com',
|
|
|
|
facebook: 'testuser',
|
|
|
|
twitter: '@testuser'
|
|
|
|
}));
|
|
|
|
|
2019-07-05 14:40:43 +03:00
|
|
|
authors.push(createUser({// Author 4
|
2018-12-27 17:45:36 +03:00
|
|
|
name: 'Author name'
|
|
|
|
}));
|
|
|
|
|
2019-07-05 14:40:43 +03:00
|
|
|
authors.push(createUser({// Author 5
|
2018-12-27 17:45:36 +03:00
|
|
|
name: 'Author name',
|
|
|
|
url: 'http://testauthorurl.com',
|
|
|
|
slug: 'author8',
|
|
|
|
profile_image: null,
|
|
|
|
website: 'http://authorwebsite.com',
|
|
|
|
facebook: 'testuser',
|
|
|
|
twitter: '@testuser'
|
|
|
|
}));
|
|
|
|
|
|
|
|
/** POSTS */
|
|
|
|
|
2019-07-05 14:40:43 +03:00
|
|
|
posts.push(createPost({// Post 0
|
2019-09-10 12:37:04 +03:00
|
|
|
meta_description: 'all about our site',
|
2018-12-27 17:45:36 +03:00
|
|
|
title: 'About',
|
|
|
|
feature_image: '/content/images/test-image-about.png',
|
|
|
|
page: true,
|
|
|
|
authors: [authors[0]],
|
|
|
|
primary_author: authors[0]
|
|
|
|
}));
|
2018-06-12 21:26:16 +03:00
|
|
|
|
2019-07-05 14:40:43 +03:00
|
|
|
posts.push(createPost({// Post 1
|
2019-09-10 12:37:04 +03:00
|
|
|
meta_description: 'all about our site',
|
2018-12-27 17:45:36 +03:00
|
|
|
title: 'About',
|
|
|
|
feature_image: '/content/images/test-image-about.png',
|
|
|
|
og_image: '/content/images/test-og-image.png',
|
|
|
|
og_title: 'Custom Facebook title',
|
|
|
|
og_description: 'Custom Facebook description',
|
|
|
|
twitter_image: '/content/images/test-twitter-image.png',
|
|
|
|
twitter_title: 'Custom Twitter title',
|
|
|
|
twitter_description: 'Custom Twitter description',
|
|
|
|
page: true,
|
|
|
|
authors: [authors[0]],
|
|
|
|
primary_author: authors[0]
|
|
|
|
}));
|
|
|
|
|
2019-07-05 14:40:43 +03:00
|
|
|
posts.push(createPost({// Post 2
|
2019-09-10 12:37:04 +03:00
|
|
|
meta_description: 'site description',
|
2018-12-27 17:45:36 +03:00
|
|
|
title: 'Welcome to Ghost',
|
|
|
|
feature_image: '/content/images/test-image.png',
|
|
|
|
og_title: 'Custom Facebook title',
|
|
|
|
og_description: 'Custom Facebook description',
|
|
|
|
twitter_image: '/content/images/test-twitter-image.png',
|
|
|
|
published_at: moment('2008-05-31T19:18:15').toDate(),
|
|
|
|
updated_at: moment('2014-10-06T15:23:54').toDate(),
|
|
|
|
tags: [
|
|
|
|
createTag({name: 'tag1'}),
|
|
|
|
createTag({name: 'tag2'}),
|
|
|
|
createTag({name: 'tag3'})
|
|
|
|
],
|
|
|
|
authors: [authors[1]],
|
|
|
|
primary_author: authors[1]
|
|
|
|
}));
|
|
|
|
|
2019-07-05 14:40:43 +03:00
|
|
|
posts.push(createPost({// Post 3
|
2019-09-10 12:37:04 +03:00
|
|
|
meta_description: 'site description',
|
2018-12-27 17:45:36 +03:00
|
|
|
custom_excerpt: 'post custom excerpt',
|
|
|
|
title: 'Welcome to Ghost',
|
|
|
|
feature_image: '/content/images/test-image.png',
|
|
|
|
og_image: '/content/images/test-facebook-image.png',
|
|
|
|
twitter_image: '/content/images/test-twitter-image.png',
|
|
|
|
twitter_title: 'Custom Twitter title',
|
|
|
|
tags: [
|
|
|
|
createTag({name: 'tag1'}),
|
|
|
|
createTag({name: 'tag2'}),
|
|
|
|
createTag({name: 'tag3'})
|
|
|
|
],
|
|
|
|
authors: [
|
|
|
|
authors[2]
|
|
|
|
],
|
|
|
|
primary_author: authors[2]
|
|
|
|
}));
|
|
|
|
|
2019-07-05 14:40:43 +03:00
|
|
|
posts.push(createPost({// Post 4
|
2018-12-27 17:45:36 +03:00
|
|
|
title: 'Welcome to Ghost',
|
|
|
|
mobiledoc: testUtils.DataGenerator.markdownToMobiledoc('This is a short post'),
|
|
|
|
authors: [
|
|
|
|
authors[3]
|
|
|
|
],
|
|
|
|
primary_author: authors[3]
|
|
|
|
}));
|
|
|
|
|
2019-07-05 14:40:43 +03:00
|
|
|
posts.push(createPost({// Post 5
|
2019-09-10 12:37:04 +03:00
|
|
|
meta_description: 'site description',
|
2018-12-27 17:45:36 +03:00
|
|
|
title: 'Welcome to Ghost',
|
|
|
|
feature_image: '/content/images/test-image.png',
|
|
|
|
og_image: '/content/images/test-facebook-image.png',
|
|
|
|
og_title: 'Custom Facebook title',
|
|
|
|
twitter_image: '/content/images/test-twitter-image.png',
|
|
|
|
twitter_title: 'Custom Twitter title',
|
|
|
|
tags: [
|
|
|
|
createTag({name: 'tag1'}),
|
|
|
|
createTag({name: 'tag2'}),
|
|
|
|
createTag({name: 'tag3'})
|
|
|
|
],
|
|
|
|
authors: [
|
|
|
|
authors[3]
|
|
|
|
],
|
|
|
|
primary_author: authors[3]
|
|
|
|
}));
|
|
|
|
|
2019-07-05 14:40:43 +03:00
|
|
|
posts.push(createPost({// Post 6
|
2019-09-10 12:37:04 +03:00
|
|
|
meta_description: 'site "test" description',
|
2018-12-27 17:45:36 +03:00
|
|
|
title: 'title',
|
|
|
|
meta_title: 'Welcome to Ghost "test"',
|
|
|
|
feature_image: '/content/images/test-image.png',
|
|
|
|
tags: [
|
|
|
|
createTag({name: 'tag1'}),
|
|
|
|
createTag({name: 'tag2'}),
|
|
|
|
createTag({name: 'tag3'})
|
|
|
|
],
|
|
|
|
authors: [
|
|
|
|
authors[3]
|
|
|
|
],
|
|
|
|
primary_author: authors[3]
|
|
|
|
}));
|
|
|
|
|
2019-07-05 14:40:43 +03:00
|
|
|
posts.push(createPost({// Post 7
|
2019-09-10 12:37:04 +03:00
|
|
|
meta_description: 'site description',
|
2018-12-27 17:45:36 +03:00
|
|
|
title: 'Welcome to Ghost',
|
|
|
|
feature_image: '/content/images/test-image.png',
|
|
|
|
tags: [],
|
|
|
|
authors: [
|
|
|
|
authors[3]
|
|
|
|
],
|
|
|
|
primary_author: authors[3]
|
|
|
|
}));
|
|
|
|
|
2019-07-05 14:40:43 +03:00
|
|
|
posts.push(createPost({// Post 8
|
2019-09-10 12:37:04 +03:00
|
|
|
meta_description: 'site description',
|
2018-12-27 17:45:36 +03:00
|
|
|
title: 'Welcome to Ghost',
|
|
|
|
feature_image: null,
|
|
|
|
tags: [
|
|
|
|
createTag({name: 'tag1'}),
|
|
|
|
createTag({name: 'tag2'}),
|
|
|
|
createTag({name: 'tag3'})
|
|
|
|
],
|
|
|
|
authors: [
|
|
|
|
authors[5]
|
|
|
|
],
|
|
|
|
primary_author: authors[5]
|
|
|
|
}));
|
|
|
|
|
2019-07-05 14:40:43 +03:00
|
|
|
posts.push(createPost({// Post 9
|
2018-12-27 17:45:36 +03:00
|
|
|
title: 'Welcome to Ghost',
|
|
|
|
mobiledoc: testUtils.DataGenerator.markdownToMobiledoc('This is a short post'),
|
|
|
|
tags: [
|
|
|
|
createTag({name: 'tag1'}),
|
|
|
|
createTag({name: 'tag2'}),
|
|
|
|
createTag({name: 'tag3'})
|
|
|
|
],
|
|
|
|
authors: [
|
|
|
|
authors[4]
|
|
|
|
],
|
|
|
|
primary_author: authors[4]
|
|
|
|
}));
|
|
|
|
};
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
|
2018-03-27 17:16:15 +03:00
|
|
|
before(function () {
|
2018-12-27 17:45:36 +03:00
|
|
|
// @TODO: remove when visibility is refactored out of models
|
2018-03-27 17:16:15 +03:00
|
|
|
models.init();
|
2019-11-21 16:08:00 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
beforeEach(function () {
|
2019-01-21 19:53:44 +03:00
|
|
|
sinon.stub(urlService, 'getUrlByResourceId').returns('https://mysite.com/fakeauthor/');
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
|
2018-12-27 17:45:36 +03:00
|
|
|
// @TODO: this is a LOT of mocking :/
|
2019-01-21 19:53:44 +03:00
|
|
|
sinon.stub(routing.registry, 'getRssUrl').returns('http://localhost:65530/rss/');
|
|
|
|
sinon.stub(imageLib.imageSize, 'getImageSizeFromUrl').resolves();
|
|
|
|
sinon.stub(themes, 'getActive').returns({
|
2019-09-10 12:37:04 +03:00
|
|
|
engine: () => 'v2'
|
2019-01-03 22:30:35 +03:00
|
|
|
});
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
|
2019-01-21 19:53:44 +03:00
|
|
|
sinon.stub(settingsCache, 'get');
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
settingsCache.get.withArgs('title').returns('Ghost');
|
2019-09-10 12:37:04 +03:00
|
|
|
settingsCache.get.withArgs('description').returns('site description');
|
|
|
|
settingsCache.get.withArgs('cover_image').returns('/content/images/site-cover.png');
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
settingsCache.get.withArgs('amp').returns(true);
|
|
|
|
|
2018-12-27 17:45:36 +03:00
|
|
|
makeFixtures();
|
2018-03-27 17:16:15 +03:00
|
|
|
});
|
|
|
|
|
2019-11-21 16:08:00 +03:00
|
|
|
afterEach(function () {
|
2019-01-21 19:53:44 +03:00
|
|
|
sinon.restore();
|
2015-12-14 23:05:11 +03:00
|
|
|
configUtils.restore();
|
2015-11-04 17:20:05 +03:00
|
|
|
});
|
|
|
|
|
2014-11-28 14:09:45 +03:00
|
|
|
describe('without Code Injection', function () {
|
2019-06-18 16:13:55 +03:00
|
|
|
let sandbox;
|
|
|
|
|
2019-11-21 16:08:00 +03:00
|
|
|
beforeEach(function () {
|
2019-06-18 16:13:55 +03:00
|
|
|
sandbox = sinon.createSandbox();
|
|
|
|
|
|
|
|
testUrlUtils.stubUrlUtils({url: 'http://localhost:65530/'}, sandbox);
|
|
|
|
});
|
|
|
|
|
2019-11-21 16:08:00 +03:00
|
|
|
afterEach(function () {
|
2019-06-18 16:13:55 +03:00
|
|
|
sandbox.restore();
|
2015-02-05 16:06:36 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
it('returns meta tag string on paginated index page without structured data and schema', function (done) {
|
2017-10-26 13:03:53 +03:00
|
|
|
// @TODO: later we can extend this fn with an `meta` object e.g. locals.meta
|
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/page/2/',
|
|
|
|
context: ['paged', 'index'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2015-02-05 16:06:36 +03:00
|
|
|
should.exist(rendered);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/page\/2\/" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
2017-03-14 19:50:35 +03:00
|
|
|
rendered.string.should.not.match(/<meta name="description"/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.not.match(/<meta property="og/);
|
|
|
|
rendered.string.should.not.match(/<script type=\"application\/ld\+json\">/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('returns structured data on first index page', function (done) {
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/',
|
|
|
|
context: ['home', 'index'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2015-02-05 16:06:36 +03:00
|
|
|
should.exist(rendered);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/" \/>/);
|
2016-08-22 12:20:56 +03:00
|
|
|
rendered.string.should.match(/<meta name="referrer" content="no-referrer-when-downgrade" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="description" content="site description" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:type" content="website" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:title" content="Ghost" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:description" content="site description" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:url" content="http:\/\/localhost:65530\/" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:image" content="http:\/\/localhost:65530\/content\/images\/site-cover.png" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:card" content="summary_large_image" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:title" content="Ghost" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:description" content="site description" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/localhost:65530\/" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:image" content="http:\/\/localhost:65530\/content\/images\/site-cover.png" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
2016-05-17 21:19:32 +03:00
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
2018-03-23 06:50:28 +03:00
|
|
|
rendered.string.should.match(/"@type": "WebSite"/);
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
rendered.string.should.match(/"publisher": {\n "@type": "Organization",\n "name": "Ghost",/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/"url": "http:\/\/localhost:65530\/"/);
|
2020-05-20 09:16:20 +03:00
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/site-cover.png"\n/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/"description": "site description"/);
|
2015-02-05 16:06:36 +03:00
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
2019-07-25 12:08:29 +03:00
|
|
|
it('returns meta structured data on homepage with site metadata defined', function (done) {
|
|
|
|
settingsCache.get.withArgs('meta_description').returns('site SEO description');
|
|
|
|
|
|
|
|
settingsCache.get.withArgs('og_title').returns('facebook site title');
|
|
|
|
settingsCache.get.withArgs('og_description').returns('facebook site description');
|
|
|
|
settingsCache.get.withArgs('og_image').returns('/content/images/facebook-image.png');
|
|
|
|
|
|
|
|
settingsCache.get.withArgs('twitter_title').returns('twitter site title');
|
|
|
|
settingsCache.get.withArgs('twitter_description').returns('twitter site description');
|
|
|
|
settingsCache.get.withArgs('twitter_image').returns('/content/images/twitter-image.png');
|
|
|
|
|
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/',
|
|
|
|
context: ['home', 'index'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
|
|
|
should.exist(rendered);
|
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="referrer" content="no-referrer-when-downgrade" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="description" content="site SEO description" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:type" content="website" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:title" content="facebook site title" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:description" content="facebook site description" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:url" content="http:\/\/localhost:65530\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:image" content="http:\/\/localhost:65530\/content\/images\/facebook-image.png" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:card" content="summary_large_image" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:title" content="twitter site title" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:description" content="twitter site description" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/localhost:65530\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:image" content="http:\/\/localhost:65530\/content\/images\/twitter-image.png" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
|
|
|
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
|
|
|
rendered.string.should.match(/"@type": "WebSite"/);
|
|
|
|
rendered.string.should.match(/"publisher": {\n "@type": "Organization",\n "name": "Ghost",/);
|
|
|
|
rendered.string.should.match(/"url": "http:\/\/localhost:65530\/"/);
|
2020-05-20 09:16:20 +03:00
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/site-cover.png"\n/);
|
2019-07-25 12:08:29 +03:00
|
|
|
rendered.string.should.match(/"description": "site SEO description"/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
2016-03-30 12:41:41 +03:00
|
|
|
it('returns structured data on static page', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
2019-11-11 13:36:00 +03:00
|
|
|
post: posts[0]
|
2016-03-30 12:41:41 +03:00
|
|
|
};
|
|
|
|
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/about/',
|
|
|
|
context: ['page'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2016-03-30 12:41:41 +03:00
|
|
|
should.exist(rendered);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/about\/" \/>/);
|
2016-08-22 12:20:56 +03:00
|
|
|
rendered.string.should.match(/<meta name="referrer" content="no-referrer-when-downgrade" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="description" content="all about our site" \/>/);
|
2016-03-30 12:41:41 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:type" content="website" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:title" content="About" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:description" content="all about our site" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:url" content="http:\/\/localhost:65530\/about\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:image" content="http:\/\/localhost:65530\/content\/images\/test-image-about.png" \/>/);
|
2016-03-03 11:52:27 +03:00
|
|
|
rendered.string.should.match(/<meta property="article:author" content="https:\/\/www.facebook.com\/testuser" \/>/);
|
2016-03-30 12:41:41 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:card" content="summary_large_image" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:title" content="About" \/>/);
|
2016-03-03 11:52:27 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:creator" content="@testuser" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:description" content="all about our site" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/localhost:65530\/about\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:image" content="http:\/\/localhost:65530\/content\/images\/test-image-about.png" \/>/);
|
2016-03-30 12:41:41 +03:00
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
2016-03-30 12:41:41 +03:00
|
|
|
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
2016-05-17 21:19:32 +03:00
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
2016-03-30 12:41:41 +03:00
|
|
|
rendered.string.should.match(/"@type": "Article"/);
|
2016-05-13 15:09:32 +03:00
|
|
|
rendered.string.should.match(/"publisher": {/);
|
|
|
|
rendered.string.should.match(/"@type": "Organization"/);
|
|
|
|
rendered.string.should.match(/"name": "Ghost"/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/"url": "http:\/\/localhost:65530\/about\/"/);
|
2016-03-03 11:52:27 +03:00
|
|
|
rendered.string.should.match(/"sameAs": \[\n "http:\/\/authorwebsite.com",\n "https:\/\/www.facebook.com\/testuser",\n "https:\/\/twitter.com\/testuser"\n \]/);
|
2020-05-20 09:16:20 +03:00
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/test-image-about.png"\n/);
|
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/test-author-image.png"\n/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/"description": "all about our site"/);
|
2016-03-30 12:41:41 +03:00
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
2017-08-03 14:48:39 +03:00
|
|
|
it('returns structured data on static page with custom post structured data', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
2019-11-11 13:36:00 +03:00
|
|
|
post: posts[1]
|
2017-08-03 14:48:39 +03:00
|
|
|
};
|
|
|
|
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/about/',
|
|
|
|
context: ['page'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2017-08-03 14:48:39 +03:00
|
|
|
should.exist(rendered);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/about\/" \/>/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<meta name="referrer" content="no-referrer-when-downgrade" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="description" content="all about our site" \/>/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:type" content="website" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:title" content="Custom Facebook title" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:description" content="Custom Facebook description" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:url" content="http:\/\/localhost:65530\/about\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:image" content="http:\/\/localhost:65530\/content\/images\/test-og-image.png" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="article:author" content="https:\/\/www.facebook.com\/testuser" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:card" content="summary_large_image" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:title" content="Custom Twitter title" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:creator" content="@testuser" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:description" content="Custom Twitter description" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/localhost:65530\/about\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:image" content="http:\/\/localhost:65530\/content\/images\/test-twitter-image.png" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
|
|
|
rendered.string.should.match(/"@type": "Article"/);
|
|
|
|
rendered.string.should.match(/"publisher": {/);
|
|
|
|
rendered.string.should.match(/"@type": "Organization"/);
|
|
|
|
rendered.string.should.match(/"name": "Ghost"/);
|
|
|
|
rendered.string.should.match(/"url": "http:\/\/localhost:65530\/about\/"/);
|
|
|
|
rendered.string.should.match(/"sameAs": \[\n "http:\/\/authorwebsite.com",\n "https:\/\/www.facebook.com\/testuser",\n "https:\/\/twitter.com\/testuser"\n \]/);
|
2020-05-20 09:16:20 +03:00
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/test-image-about.png"/);
|
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/test-author-image.png"\n/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/"description": "all about our site"/);
|
2014-10-14 17:18:42 +04:00
|
|
|
|
2014-11-28 14:09:45 +03:00
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
2014-10-24 21:21:51 +04:00
|
|
|
|
2014-11-28 14:09:45 +03:00
|
|
|
it('returns structured data on post page with author image and post cover image', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
|
|
|
post: posts[2]
|
|
|
|
};
|
|
|
|
|
|
|
|
const postBk = _.cloneDeep(renderObject.post);
|
2017-10-26 13:03:53 +03:00
|
|
|
|
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/post/',
|
|
|
|
context: ['post'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const re1 = new RegExp('<meta property="article:published_time" content="' + new Date(renderObject.post.published_at).toISOString());
|
|
|
|
const re2 = new RegExp('<meta property="article:modified_time" content="' + new Date(renderObject.post.updated_at).toISOString());
|
|
|
|
const re3 = new RegExp('"datePublished": "' + new Date(renderObject.post.published_at).toISOString());
|
|
|
|
const re4 = new RegExp('"dateModified": "' + new Date(renderObject.post.updated_at).toISOString());
|
2015-02-05 16:06:36 +03:00
|
|
|
|
2014-11-28 14:09:45 +03:00
|
|
|
should.exist(rendered);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="amphtml" href="http:\/\/localhost:65530\/post\/amp\/" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="description" content="site description" \/>/);
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:type" content="article" \/>/);
|
2017-08-03 14:48:39 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:title" content="Custom Facebook title" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:description" content="Custom Facebook description" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:url" content="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:image" content="http:\/\/localhost:65530\/content\/images\/test-image.png" \/>/);
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
rendered.string.should.match(re1);
|
|
|
|
rendered.string.should.match(re2);
|
|
|
|
rendered.string.should.match(/<meta property="article:tag" content="tag1" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="article:tag" content="tag2" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="article:tag" content="tag3" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="article:author" content="https:\/\/www.facebook.com\/testuser" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:title" content="Welcome to Ghost" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:description" content="site description" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:image" content="http:\/\/localhost:65530\/content\/images\/test-twitter-image.png" \/>/);
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:creator" content="@testuser" \/>/);
|
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
|
|
|
rendered.string.should.match(/"@type": "Article"/);
|
|
|
|
rendered.string.should.match(/"publisher": {/);
|
|
|
|
rendered.string.should.match(/"@type": "Organization"/);
|
|
|
|
rendered.string.should.match(/"name": "Ghost"/);
|
|
|
|
rendered.string.should.match(/"author": {/);
|
|
|
|
rendered.string.should.match(/"@type": "Person"/);
|
|
|
|
rendered.string.should.match(/"name": "Author name"/);
|
2020-05-20 09:16:20 +03:00
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/test-author-image.png"\n/);
|
2018-12-27 17:45:36 +03:00
|
|
|
rendered.string.should.match(/"url": "https:\/\/mysite.com\/fakeauthor\/"/);
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
rendered.string.should.match(/"sameAs": \[\n "http:\/\/authorwebsite.com",\n "https:\/\/www.facebook.com\/testuser",\n "https:\/\/twitter.com\/testuser"\n \]/);
|
2017-08-01 11:39:34 +03:00
|
|
|
rendered.string.should.not.match(/"description": "Author bio"/);
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
rendered.string.should.match(/"headline": "Welcome to Ghost"/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/"url": "http:\/\/localhost:65530\/post\/"/);
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
rendered.string.should.match(re3);
|
|
|
|
rendered.string.should.match(re4);
|
2020-05-20 09:16:20 +03:00
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/test-image.png"\n/);
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
rendered.string.should.match(/"keywords": "tag1, tag2, tag3"/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/"description": "site description"/);
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
|
2017-10-26 13:03:53 +03:00
|
|
|
renderObject.post.should.eql(postBk);
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
2017-08-01 11:39:34 +03:00
|
|
|
it('returns structured data on post page with custom excerpt for description and meta description', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
|
|
|
post: posts[3]
|
|
|
|
};
|
|
|
|
|
|
|
|
const postBk = _.cloneDeep(renderObject.post);
|
2017-10-26 13:03:53 +03:00
|
|
|
|
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/post/',
|
|
|
|
context: ['post'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2017-08-01 11:39:34 +03:00
|
|
|
should.exist(rendered);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="amphtml" href="http:\/\/localhost:65530\/post\/amp\/" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="description" content="site description" \/>/);
|
2017-08-01 11:39:34 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:type" content="article" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:title" content="Welcome to Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:description" content="post custom excerpt" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:url" content="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:image" content="http:\/\/localhost:65530\/content\/images\/test-facebook-image.png" \/>/);
|
2017-08-01 11:39:34 +03:00
|
|
|
rendered.string.should.match(/<meta property="article:tag" content="tag1" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="article:tag" content="tag2" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="article:tag" content="tag3" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="article:author" content="https:\/\/www.facebook.com\/testuser" \/>/);
|
2017-08-03 14:48:39 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:title" content="Custom Twitter title" \/>/);
|
2017-08-01 11:39:34 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:description" content="post custom excerpt" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:image" content="http:\/\/localhost:65530\/content\/images\/test-twitter-image.png" \/>/);
|
2017-08-01 11:39:34 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:creator" content="@testuser" \/>/);
|
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
|
|
|
rendered.string.should.match(/"@type": "Article"/);
|
|
|
|
rendered.string.should.match(/"publisher": {/);
|
|
|
|
rendered.string.should.match(/"@type": "Organization"/);
|
|
|
|
rendered.string.should.match(/"name": "Ghost"/);
|
|
|
|
rendered.string.should.match(/"author": {/);
|
|
|
|
rendered.string.should.match(/"@type": "Person"/);
|
|
|
|
rendered.string.should.match(/"name": "Author name"/);
|
2020-05-20 09:16:20 +03:00
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/test-author-image.png"/);
|
2018-12-27 17:45:36 +03:00
|
|
|
rendered.string.should.match(/"url": "https:\/\/mysite.com\/fakeauthor\/"/);
|
2017-08-01 11:39:34 +03:00
|
|
|
rendered.string.should.match(/"sameAs": \[\n "http:\/\/authorwebsite.com",\n "https:\/\/www.facebook.com\/testuser",\n "https:\/\/twitter.com\/testuser"\n \]/);
|
|
|
|
rendered.string.should.not.match(/"description": "Author bio"/);
|
|
|
|
rendered.string.should.match(/"headline": "Welcome to Ghost"/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/"url": "http:\/\/localhost:65530\/post\/"/);
|
2020-05-20 09:16:20 +03:00
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/test-image.png"/);
|
2017-08-01 11:39:34 +03:00
|
|
|
rendered.string.should.match(/"keywords": "tag1, tag2, tag3"/);
|
|
|
|
rendered.string.should.match(/"description": "post custom excerpt"/);
|
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
2017-08-01 11:39:34 +03:00
|
|
|
|
2017-10-26 13:03:53 +03:00
|
|
|
renderObject.post.should.eql(postBk);
|
2017-08-01 11:39:34 +03:00
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('returns structured data on post page with fall back excerpt if no meta description provided', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
|
|
|
post: posts[4]
|
|
|
|
};
|
|
|
|
|
|
|
|
const postBk = _.cloneDeep(renderObject.post);
|
2017-10-26 13:03:53 +03:00
|
|
|
|
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/post/',
|
|
|
|
context: ['post'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2017-08-01 11:39:34 +03:00
|
|
|
should.exist(rendered);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="amphtml" href="http:\/\/localhost:65530\/post\/amp\/" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.not.match(/<meta name="description" content="site description" \/>/);
|
2017-08-01 11:39:34 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:type" content="article" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:title" content="Welcome to Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:description" content="This is a short post" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:url" content="http:\/\/localhost:65530\/post\/" \/>/);
|
2017-08-01 11:39:34 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:title" content="Welcome to Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:description" content="This is a short post" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/localhost:65530\/post\/" \/>/);
|
2017-08-01 11:39:34 +03:00
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
|
|
|
rendered.string.should.match(/"@type": "Article"/);
|
|
|
|
rendered.string.should.match(/"publisher": {/);
|
|
|
|
rendered.string.should.match(/"@type": "Organization"/);
|
|
|
|
rendered.string.should.match(/"name": "Ghost"/);
|
|
|
|
rendered.string.should.match(/"author": {/);
|
|
|
|
rendered.string.should.match(/"@type": "Person"/);
|
|
|
|
rendered.string.should.match(/"name": "Author name"/);
|
2018-12-27 17:45:36 +03:00
|
|
|
rendered.string.should.match(/"url": "https:\/\/mysite.com\/fakeauthor\/"/);
|
2017-08-01 11:39:34 +03:00
|
|
|
rendered.string.should.not.match(/"description": "Author bio"/);
|
|
|
|
rendered.string.should.match(/"headline": "Welcome to Ghost"/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/"url": "http:\/\/localhost:65530\/post\/"/);
|
2017-08-01 11:39:34 +03:00
|
|
|
rendered.string.should.match(/"description": "This is a short post"/);
|
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
2017-08-01 11:39:34 +03:00
|
|
|
|
2017-10-26 13:03:53 +03:00
|
|
|
renderObject.post.should.eql(postBk);
|
2017-08-01 11:39:34 +03:00
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
it('returns structured data on AMP post page with author image and post cover image', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
|
|
|
post: posts[5]
|
|
|
|
};
|
|
|
|
|
|
|
|
const postBk = _.cloneDeep(renderObject.post);
|
2017-10-26 13:03:53 +03:00
|
|
|
|
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/post/amp/',
|
|
|
|
context: ['amp', 'post'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
should.exist(rendered);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.not.match(/<link rel="amphtml" href="http:\/\/localhost:65530\/post\/amp\/" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="description" content="site description" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:type" content="article" \/>/);
|
2017-08-03 14:48:39 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:title" content="Custom Facebook title" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:description" content="site description" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:url" content="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:image" content="http:\/\/localhost:65530\/content\/images\/test-facebook-image.png" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta property="article:tag" content="tag1" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="article:tag" content="tag2" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="article:tag" content="tag3" \/>/);
|
2016-03-03 11:52:27 +03:00
|
|
|
rendered.string.should.match(/<meta property="article:author" content="https:\/\/www.facebook.com\/testuser" \/>/);
|
2017-08-03 14:48:39 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:title" content="Custom Twitter title" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:description" content="site description" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:image" content="http:\/\/localhost:65530\/content\/images\/test-twitter-image.png" \/>/);
|
2016-03-03 11:52:27 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:creator" content="@testuser" \/>/);
|
2016-05-17 21:19:32 +03:00
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/"@type": "Article"/);
|
2016-05-13 15:09:32 +03:00
|
|
|
rendered.string.should.match(/"publisher": {/);
|
|
|
|
rendered.string.should.match(/"@type": "Organization"/);
|
|
|
|
rendered.string.should.match(/"name": "Ghost"/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/"author": {/);
|
|
|
|
rendered.string.should.match(/"@type": "Person"/);
|
|
|
|
rendered.string.should.match(/"name": "Author name"/);
|
2020-05-20 09:16:20 +03:00
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/test-author-image.png"/);
|
2018-12-27 17:45:36 +03:00
|
|
|
rendered.string.should.match(/"url": "https:\/\/mysite.com\/fakeauthor\/"/);
|
2016-03-03 11:52:27 +03:00
|
|
|
rendered.string.should.match(/"sameAs": \[\n "http:\/\/authorwebsite.com",\n "https:\/\/www.facebook.com\/testuser",\n "https:\/\/twitter.com\/testuser"\n \]/);
|
2017-08-01 11:39:34 +03:00
|
|
|
rendered.string.should.not.match(/"description": "Author bio"/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/"headline": "Welcome to Ghost"/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/"url": "http:\/\/localhost:65530\/post\/"/);
|
2020-05-20 09:16:20 +03:00
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/test-image.png"/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/"keywords": "tag1, tag2, tag3"/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/"description": "site description"/);
|
2016-05-17 21:19:32 +03:00
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
2014-11-28 14:09:45 +03:00
|
|
|
|
2017-10-26 13:03:53 +03:00
|
|
|
renderObject.post.should.eql(postBk);
|
2015-12-15 16:04:06 +03:00
|
|
|
|
2014-11-28 14:09:45 +03:00
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('returns structured data if metaTitle and metaDescription have double quotes', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
post: posts[6]
|
2014-11-28 14:09:45 +03:00
|
|
|
};
|
|
|
|
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/post/',
|
|
|
|
context: ['post'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2014-11-28 14:09:45 +03:00
|
|
|
should.exist(rendered);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="amphtml" href="http:\/\/localhost:65530\/post\/amp\/" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="description" content="site "test" description" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:type" content="article" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:title" content="Welcome to Ghost "test"" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:description" content="site "test" description" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:url" content="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:image" content="http:\/\/localhost:65530\/content\/images\/test-image.png" \/>/);
|
2016-03-03 11:52:27 +03:00
|
|
|
rendered.string.should.match(/<meta property="article:author" content="https:\/\/www.facebook.com\/testuser" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta property="article:tag" content="tag1" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="article:tag" content="tag2" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="article:tag" content="tag3" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:card" content="summary_large_image" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:title" content="Welcome to Ghost "test"" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:description" content="site "test" description" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/localhost:65530\/post\/" \/>/);
|
2016-03-03 11:52:27 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:creator" content="@testuser" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:image" content="http:\/\/localhost:65530\/content\/images\/test-image.png" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
2016-05-17 21:19:32 +03:00
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/"@type": "Article"/);
|
2016-05-13 15:09:32 +03:00
|
|
|
rendered.string.should.match(/"publisher": {/);
|
|
|
|
rendered.string.should.match(/"@type": "Organization"/);
|
|
|
|
rendered.string.should.match(/"name": "Ghost"/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/"author": {/);
|
|
|
|
rendered.string.should.match(/"@type": "Person"/);
|
|
|
|
rendered.string.should.match(/"name": "Author name"/);
|
2020-05-20 09:16:20 +03:00
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/test-author-image.png"/);
|
2018-12-27 17:45:36 +03:00
|
|
|
rendered.string.should.match(/"url": "https:\/\/mysite.com\/fakeauthor\/"/);
|
2016-03-03 11:52:27 +03:00
|
|
|
rendered.string.should.match(/"sameAs": \[\n "http:\/\/authorwebsite.com",\n "https:\/\/www.facebook.com\/testuser",\n "https:\/\/twitter.com\/testuser"\n \]/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/"headline": "Welcome to Ghost "test""/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/"url": "http:\/\/localhost:65530\/post\/"/);
|
2016-05-17 21:19:32 +03:00
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
2020-05-20 09:16:20 +03:00
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/test-image.png"/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/"keywords": "tag1, tag2, tag3"/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/"description": "site "test" description"/);
|
2016-05-17 21:19:32 +03:00
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
2014-11-28 14:09:45 +03:00
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('returns structured data without tags if there are no tags', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
post: posts[7]
|
2014-11-28 14:09:45 +03:00
|
|
|
};
|
|
|
|
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/post/',
|
|
|
|
context: ['post'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2014-11-28 14:09:45 +03:00
|
|
|
should.exist(rendered);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="amphtml" href="http:\/\/localhost:65530\/post\/amp\/" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="description" content="site description" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:type" content="article" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:title" content="Welcome to Ghost" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:description" content="site description" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:url" content="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:image" content="http:\/\/localhost:65530\/content\/images\/test-image.png" \/>/);
|
2016-03-03 11:52:27 +03:00
|
|
|
rendered.string.should.match(/<meta property="article:author" content="https:\/\/www.facebook.com\/testuser" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.not.match(/<meta property="article:tag"/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:card" content="summary_large_image" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:title" content="Welcome to Ghost" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:description" content="site description" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:image" content="http:\/\/localhost:65530\/content\/images\/test-image.png" \/>/);
|
2016-03-03 11:52:27 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:creator" content="@testuser" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
2016-05-17 21:19:32 +03:00
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/"@type": "Article"/);
|
2016-05-13 15:09:32 +03:00
|
|
|
rendered.string.should.match(/"publisher": {/);
|
|
|
|
rendered.string.should.match(/"@type": "Organization"/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/"author": {/);
|
|
|
|
rendered.string.should.match(/"@type": "Person"/);
|
|
|
|
rendered.string.should.match(/"name": "Author name"/);
|
2020-05-20 09:16:20 +03:00
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/test-author-image.png"/);
|
2018-12-27 17:45:36 +03:00
|
|
|
rendered.string.should.match(/"url": "https:\/\/mysite.com\/fakeauthor\/"/);
|
2016-03-03 11:52:27 +03:00
|
|
|
rendered.string.should.match(/"sameAs": \[\n "http:\/\/authorwebsite.com",\n "https:\/\/www.facebook.com\/testuser",\n "https:\/\/twitter.com\/testuser"\n \]/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/"headline": "Welcome to Ghost"/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/"url": "http:\/\/localhost:65530\/post\/"/);
|
2016-05-17 21:19:32 +03:00
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
2020-05-20 09:16:20 +03:00
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/test-image.png"/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.not.match(/"keywords":/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/"description": "site description"/);
|
2016-05-17 21:19:32 +03:00
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
2014-11-28 14:09:45 +03:00
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
2014-10-14 17:18:42 +04:00
|
|
|
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
it('returns structured data on post page with null author image and post cover image', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
post: posts[8]
|
|
|
|
};
|
|
|
|
|
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/post/',
|
|
|
|
context: ['post'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
|
|
|
should.exist(rendered);
|
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="amphtml" href="http:\/\/localhost:65530\/post\/amp\/" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="description" content="site description" \/>/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:type" content="article" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:title" content="Welcome to Ghost" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:description" content="site description" \/>/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:url" content="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="article:author" content="https:\/\/www.facebook.com\/testuser" \/>/);
|
2021-02-05 08:50:11 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:image"/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<meta property="article:tag" content="tag1" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="article:tag" content="tag2" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="article:tag" content="tag3" \/>/);
|
2021-02-05 08:50:11 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:card" content="summary_large_image" \/>/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:title" content="Welcome to Ghost" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:description" content="site description" \/>/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:creator" content="@testuser" \/>/);
|
2021-02-05 08:50:11 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:image"/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
|
|
|
rendered.string.should.match(/"@type": "Article"/);
|
|
|
|
rendered.string.should.match(/"publisher": {/);
|
|
|
|
rendered.string.should.match(/"@type": "Organization"/);
|
|
|
|
rendered.string.should.match(/"name": "Ghost"/);
|
|
|
|
rendered.string.should.match(/"author": {/);
|
|
|
|
rendered.string.should.match(/"@type": "Person"/);
|
|
|
|
rendered.string.should.match(/"name": "Author name"/);
|
|
|
|
rendered.string.should.not.match(/"image\"/);
|
2018-12-27 17:45:36 +03:00
|
|
|
rendered.string.should.match(/"url": "https:\/\/mysite.com\/fakeauthor\/"/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/"sameAs": \[\n "http:\/\/authorwebsite.com",\n "https:\/\/www.facebook.com\/testuser",\n "https:\/\/twitter.com\/testuser"\n \]/);
|
|
|
|
rendered.string.should.match(/"headline": "Welcome to Ghost"/);
|
|
|
|
rendered.string.should.match(/"url": "http:\/\/localhost:65530\/post\/"/);
|
|
|
|
rendered.string.should.match(/"keywords": "tag1, tag2, tag3"/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/"description": "site description"/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('returns twitter and facebook descriptions even if no meta description available', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
post: posts[9]
|
|
|
|
};
|
|
|
|
|
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/post/',
|
|
|
|
context: ['post'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
|
|
|
should.exist(rendered);
|
|
|
|
rendered.string.should.not.match(/<meta name="description" /);
|
|
|
|
rendered.string.should.match(/<link rel="amphtml" href="http:\/\/localhost:65530\/post\/amp\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:description" content="This is a short post" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:description" content="This is a short post" \/>/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('returns canonical URL', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
post: posts[9]
|
|
|
|
};
|
|
|
|
|
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/about/',
|
|
|
|
context: ['page'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
|
|
|
should.exist(rendered);
|
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/about\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('returns next & prev URL correctly for middle page', function (done) {
|
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: {
|
|
|
|
pagination: {total: 4, page: 3, next: 4, prev: 2}
|
|
|
|
},
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/page/3/',
|
|
|
|
context: ['paged', 'index'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
|
|
|
should.exist(rendered);
|
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/page\/3\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="prev" href="http:\/\/localhost:65530\/page\/2\/" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="next" href="http:\/\/localhost:65530\/page\/4\/" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
|
|
|
rendered.string.should.not.match(/<meta property="og/);
|
|
|
|
rendered.string.should.not.match(/<script type=\"application\/ld\+json\">/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('returns next & prev URL correctly for second page', function (done) {
|
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: {
|
|
|
|
pagination: {total: 3, page: 2, next: 3, prev: 1}
|
|
|
|
},
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/page/2/',
|
|
|
|
context: ['paged', 'index'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
|
|
|
should.exist(rendered);
|
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/page\/2\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="prev" href="http:\/\/localhost:65530\/" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="next" href="http:\/\/localhost:65530\/page\/3\/" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
|
|
|
rendered.string.should.not.match(/<meta property="og/);
|
|
|
|
rendered.string.should.not.match(/<meta name="description" /);
|
|
|
|
rendered.string.should.not.match(/<script type=\"application\/ld\+json\">/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('returns structured data and schema first tag page with meta description and meta title', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
tag: tags[0]
|
|
|
|
};
|
|
|
|
|
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/tag/tagtitle/',
|
|
|
|
context: ['tag'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
|
|
|
should.exist(rendered);
|
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/tag\/tagtitle\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="description" content="tag meta description" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:type" content="website" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:title" content="tag meta title" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:description" content="tag meta description" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:url" content="http:\/\/localhost:65530\/tag\/tagtitle\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:image" content="http:\/\/localhost:65530\/content\/images\/tag-image.png" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:card" content="summary_large_image" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:title" content="tag meta title" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:description" content="tag meta description" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/localhost:65530\/tag\/tagtitle\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:image" content="http:\/\/localhost:65530\/content\/images\/tag-image.png" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
|
|
|
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
|
|
|
rendered.string.should.match(/"@type": "Series"/);
|
|
|
|
rendered.string.should.match(/"publisher": {\n "@type": "Organization",\n "name": "Ghost",/);
|
|
|
|
rendered.string.should.match(/"url": "http:\/\/localhost:65530\/tag\/tagtitle\/"/);
|
2020-05-20 09:16:20 +03:00
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/tag-image.png"/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/"name": "tagtitle"/);
|
|
|
|
rendered.string.should.match(/"description": "tag meta description"/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('tag first page without meta data if no meta title and meta description, but model description provided', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
tag: tags[1]
|
2014-11-28 14:09:45 +03:00
|
|
|
};
|
2014-10-14 17:18:42 +04:00
|
|
|
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
relativeUrl: '/tag/tagtitle/',
|
|
|
|
context: ['tag'],
|
2017-10-26 13:03:53 +03:00
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2014-11-28 14:09:45 +03:00
|
|
|
should.exist(rendered);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/tag\/tagtitle\/" \/>/);
|
2019-11-21 16:08:00 +03:00
|
|
|
rendered.string.should.match(/<meta name="description" content="tag description"/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:type" content="website" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:title" content="tagtitle - Ghost" \/>/);
|
2019-11-21 16:08:00 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:description" content="tag description"/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:url" content="http:\/\/localhost:65530\/tag\/tagtitle\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:image" content="http:\/\/localhost:65530\/content\/images\/tag-image.png" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:card" content="summary_large_image" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:title" content="tagtitle - Ghost" \/>/);
|
2019-11-21 16:08:00 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:description" content="tag description"/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/localhost:65530\/tag\/tagtitle\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:image" content="http:\/\/localhost:65530\/content\/images\/tag-image.png" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
|
|
|
rendered.string.should.match(/"@type": "Series"/);
|
|
|
|
rendered.string.should.match(/"publisher": {\n "@type": "Organization",\n "name": "Ghost",/);
|
|
|
|
rendered.string.should.match(/"url": "http:\/\/localhost:65530\/tag\/tagtitle\/"/);
|
2020-05-20 09:16:20 +03:00
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/tag-image.png"/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/"name": "tagtitle"/);
|
2014-10-10 18:54:07 +04:00
|
|
|
|
2014-11-28 14:09:45 +03:00
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
2014-10-10 18:54:07 +04:00
|
|
|
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
it('tag first page without meta and model description returns no description fields', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
tag: tags[2]
|
|
|
|
};
|
|
|
|
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
renderObject: renderObject,
|
2017-10-26 13:03:53 +03:00
|
|
|
locals: {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
relativeUrl: '/tag/tagtitle/',
|
|
|
|
context: ['tag'],
|
2017-10-26 13:03:53 +03:00
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2016-03-21 01:33:46 +03:00
|
|
|
should.exist(rendered);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.not.match(/<meta name="description"/);
|
|
|
|
rendered.string.should.not.match(/<meta property="og:description"/);
|
|
|
|
rendered.string.should.not.match(/<meta name="twitter:description"/);
|
|
|
|
rendered.string.should.not.match(/"description":/);
|
2016-03-21 01:33:46 +03:00
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
it('does not return structured data on paginated tag pages', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
tag: tags[3]
|
2016-02-18 14:47:08 +03:00
|
|
|
};
|
|
|
|
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
relativeUrl: '/tag/tagtitle/page/2/',
|
|
|
|
context: ['paged', 'tag'],
|
2017-10-26 13:03:53 +03:00
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2016-02-18 14:47:08 +03:00
|
|
|
should.exist(rendered);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/tag\/tagtitle\/page\/2\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
|
|
|
rendered.string.should.not.match(/<meta name="description" content="tag meta description" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
|
|
|
rendered.string.should.not.match(/<meta property="og/);
|
|
|
|
rendered.string.should.not.match(/<script type=\"application\/ld\+json\">/);
|
2016-02-18 14:47:08 +03:00
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
it('returns structured data and schema on first author page with cover image', function (done) {
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
renderObject: {author: users[0]},
|
2017-10-26 13:03:53 +03:00
|
|
|
locals: {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
// @TODO: WHY?
|
|
|
|
relativeUrl: '/author/authorname/',
|
|
|
|
context: ['author'],
|
2017-10-26 13:03:53 +03:00
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2014-11-28 14:09:45 +03:00
|
|
|
should.exist(rendered);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/author\/authorname\/" \/>/);
|
2019-11-21 16:08:00 +03:00
|
|
|
rendered.string.should.match(/<meta name="description" content="Author bio"/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:type" content="profile" \/>/);
|
2019-11-21 16:08:00 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:description" content="Author bio"/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:url" content="http:\/\/localhost:65530\/author\/authorname\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:image" content="http:\/\/localhost:65530\/content\/images\/author-cover-image.png" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="article:author" content="https:\/\/www.facebook.com\/testuser\" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:card" content="summary_large_image" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:title" content="Author name - Ghost" \/>/);
|
2019-11-21 16:08:00 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:description" content="Author bio"/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/localhost:65530\/author\/authorname\/" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:creator" content="@testuser" \/>/);
|
|
|
|
rendered.string.should.match(/<meta name="twitter:image" content="http:\/\/localhost:65530\/content\/images\/author-cover-image.png" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
|
|
|
rendered.string.should.match(/"@context": "https:\/\/schema.org"/);
|
|
|
|
rendered.string.should.match(/"@type": "Person"/);
|
|
|
|
rendered.string.should.match(/"sameAs": \[\n "http:\/\/authorwebsite.com",\n "https:\/\/www.facebook.com\/testuser",\n "https:\/\/twitter.com\/testuser"\n \]/);
|
2018-12-27 17:45:36 +03:00
|
|
|
rendered.string.should.match(/"url": "https:\/\/mysite.com\/fakeauthor\/"/);
|
2020-05-20 09:16:20 +03:00
|
|
|
rendered.string.should.match(/"image": {\n "@type": "ImageObject",\n "url": "http:\/\/localhost:65530\/content\/images\/author-cover-image.png"/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/"name": "Author name"/);
|
2014-10-10 18:54:07 +04:00
|
|
|
|
2014-11-28 14:09:45 +03:00
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
it('does not return structured data on paginated author pages', function (done) {
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
renderObject: {author: users[1]},
|
2017-10-26 13:03:53 +03:00
|
|
|
locals: {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
// @TODO: WHY?
|
|
|
|
relativeUrl: '/author/authorname1/page/2/',
|
|
|
|
context: ['paged', 'author'],
|
2017-10-26 13:03:53 +03:00
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2014-11-28 14:09:45 +03:00
|
|
|
should.exist(rendered);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/author\/authorname1\/page\/2\/" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.not.match(/<meta name="description" /);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.not.match(/<meta property="og/);
|
|
|
|
rendered.string.should.not.match(/<script type=\"application\/ld\+json\">/);
|
|
|
|
|
2014-11-28 14:09:45 +03:00
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
it('returns meta tag string even if safeVersion is invalid', function (done) {
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
locals: {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
context: [],
|
|
|
|
safeVersion: '0.9'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
|
|
|
should.exist(rendered);
|
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.9" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
2018-09-17 12:29:47 +03:00
|
|
|
it('disallows indexing for preview pages', function (done) {
|
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
locals: {
|
|
|
|
context: ['preview', 'post']
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
|
|
|
should.exist(rendered);
|
|
|
|
rendered.string.should.match(/<meta name="robots" content="noindex,nofollow" \/>/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('implicit indexing settings for non-preview pages', function (done) {
|
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
locals: {
|
|
|
|
context: ['featured', 'paged', 'index', 'post', 'amp', 'home', 'unicorn']
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
|
|
|
should.exist(rendered);
|
|
|
|
rendered.string.should.not.match(/<meta name="robots" content="noindex,nofollow" \/>/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
it('outputs structured data but not schema for custom collection', function (done) {
|
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/featured/',
|
|
|
|
context: ['featured'],
|
2017-10-26 13:03:53 +03:00
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2014-11-28 14:09:45 +03:00
|
|
|
should.exist(rendered);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/featured\/" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:type" content="website" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:title" content="Ghost" \/>/);
|
|
|
|
rendered.string.should.match(/<meta property="og:url" content="http:\/\/localhost:65530\/featured\/" \/>/);
|
|
|
|
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.not.match(/<script type=\"application\/ld\+json\">/);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
rendered.string.should.not.match(/<meta name="description" /);
|
2015-02-05 16:06:36 +03:00
|
|
|
|
2014-11-28 14:09:45 +03:00
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
2019-06-18 16:13:55 +03:00
|
|
|
});
|
2014-11-28 14:09:45 +03:00
|
|
|
|
2019-09-10 12:37:04 +03:00
|
|
|
describe('with /site subdirectory', function () {
|
2019-06-18 16:13:55 +03:00
|
|
|
let sandbox;
|
2017-02-03 16:15:11 +03:00
|
|
|
|
2019-11-21 16:08:00 +03:00
|
|
|
beforeEach(function () {
|
2019-06-18 16:13:55 +03:00
|
|
|
sandbox = sinon.createSandbox();
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
settingsCache.get.withArgs('icon').returns('/content/images/favicon.png');
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
|
2019-09-10 12:37:04 +03:00
|
|
|
testUrlUtils.stubUrlUtils({url: 'http://localhost:65530/site'}, sandbox);
|
2014-10-10 18:54:07 +04:00
|
|
|
|
2019-09-10 12:37:04 +03:00
|
|
|
routing.registry.getRssUrl.returns('http://localhost:65530/site/rss/');
|
2019-06-18 16:13:55 +03:00
|
|
|
});
|
|
|
|
|
2019-11-21 16:08:00 +03:00
|
|
|
afterEach(function () {
|
2019-06-18 16:13:55 +03:00
|
|
|
sandbox.restore();
|
|
|
|
routing.registry.getRssUrl.returns('http://localhost:65530/rss/');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('returns correct rss url with subdirectory', function (done) {
|
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
locals: {
|
|
|
|
context: ['paged', 'index'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
|
|
|
should.exist(rendered);
|
2020-06-30 17:07:08 +03:00
|
|
|
rendered.string.should.match(/<link rel="icon" href="\/site\/favicon.png" type="image\/png" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/site\/" \/>/);
|
2019-06-18 16:13:55 +03:00
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/site\/rss\/" \/>/);
|
2019-06-18 16:13:55 +03:00
|
|
|
rendered.string.should.not.match(/<meta name="description" /);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
2014-11-28 14:09:45 +03:00
|
|
|
});
|
2014-10-10 18:54:07 +04:00
|
|
|
});
|
|
|
|
|
2016-07-14 19:14:59 +03:00
|
|
|
describe('with changed origin in config file', function () {
|
2019-06-18 16:13:55 +03:00
|
|
|
let sandbox;
|
|
|
|
|
2019-11-21 16:08:00 +03:00
|
|
|
beforeEach(function () {
|
2019-06-18 16:13:55 +03:00
|
|
|
sandbox = sinon.createSandbox();
|
|
|
|
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
settingsCache.get.withArgs('icon').returns('/content/images/favicon.png');
|
2017-02-03 16:15:11 +03:00
|
|
|
|
2016-07-14 19:14:59 +03:00
|
|
|
configUtils.set({
|
|
|
|
referrerPolicy: 'origin'
|
|
|
|
});
|
2019-06-18 16:13:55 +03:00
|
|
|
|
2019-09-10 12:37:04 +03:00
|
|
|
testUrlUtils.stubUrlUtils({url: 'http://localhost:65530/site'}, sandbox);
|
2019-06-18 16:13:55 +03:00
|
|
|
});
|
|
|
|
|
2019-11-21 16:08:00 +03:00
|
|
|
afterEach(function () {
|
2019-06-18 16:13:55 +03:00
|
|
|
sandbox.restore();
|
2016-07-14 19:14:59 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
it('contains the changed origin', function (done) {
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
locals: {
|
|
|
|
context: ['paged', 'index'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2016-07-14 19:14:59 +03:00
|
|
|
should.exist(rendered);
|
2020-06-30 17:07:08 +03:00
|
|
|
rendered.string.should.match(/<link rel="icon" href="\/site\/favicon.png" type="image\/png" \/>/);
|
2016-07-14 19:14:59 +03:00
|
|
|
rendered.string.should.match(/<meta name="referrer" content="origin" \/>/);
|
2017-03-14 19:50:35 +03:00
|
|
|
rendered.string.should.not.match(/<meta name="description" /);
|
2016-07-14 19:14:59 +03:00
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-05 16:06:36 +03:00
|
|
|
describe('with useStructuredData is set to false in config file', function () {
|
2019-06-18 16:13:55 +03:00
|
|
|
let sandbox;
|
|
|
|
|
2019-11-21 16:08:00 +03:00
|
|
|
beforeEach(function () {
|
2019-06-18 16:13:55 +03:00
|
|
|
sandbox = sinon.createSandbox();
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
settingsCache.get.withArgs('icon').returns('/content/images/favicon.png');
|
2017-02-03 16:15:11 +03:00
|
|
|
|
2015-12-14 23:05:11 +03:00
|
|
|
configUtils.set({
|
2015-02-05 16:06:36 +03:00
|
|
|
privacy: {
|
|
|
|
useStructuredData: false
|
|
|
|
}
|
|
|
|
});
|
2019-06-18 16:13:55 +03:00
|
|
|
|
|
|
|
testUrlUtils.stubUrlUtils({url: 'http://localhost:65530/'}, sandbox);
|
|
|
|
});
|
|
|
|
|
2019-11-21 16:08:00 +03:00
|
|
|
afterEach(function () {
|
2019-06-18 16:13:55 +03:00
|
|
|
sandbox.restore();
|
2015-02-05 16:06:36 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
it('does not return structured data', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
post: posts[2]
|
2015-02-05 16:06:36 +03:00
|
|
|
};
|
|
|
|
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/post/',
|
|
|
|
context: ['post'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2015-02-05 16:06:36 +03:00
|
|
|
should.exist(rendered);
|
2020-06-30 17:07:08 +03:00
|
|
|
rendered.string.should.match(/<link rel="icon" href="\/favicon.png" type="image\/png" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/post\/" \/>/);
|
|
|
|
rendered.string.should.match(/<link rel="amphtml" href="http:\/\/localhost:65530\/post\/amp\/" \/>/);
|
2019-09-10 12:37:04 +03:00
|
|
|
rendered.string.should.match(/<meta name="description" content="site description" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.not.match(/<meta property="og/);
|
|
|
|
rendered.string.should.not.match(/<script type=\"application\/ld\+json\">/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2014-11-28 14:09:45 +03:00
|
|
|
describe('with Code Injection', function () {
|
2019-06-18 16:13:55 +03:00
|
|
|
let sandbox;
|
|
|
|
|
2019-11-21 16:08:00 +03:00
|
|
|
beforeEach(function () {
|
2019-06-18 16:13:55 +03:00
|
|
|
sandbox = sinon.createSandbox();
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
settingsCache.get.withArgs('icon').returns('/content/images/favicon.png');
|
2020-07-01 19:58:12 +03:00
|
|
|
settingsCache.get.withArgs('codeinjection_head').returns('<style>body {background: red;}</style>');
|
2017-02-03 16:15:11 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
testUrlUtils.stubUrlUtils({url: 'http://localhost:65530/'}, sandbox);
|
|
|
|
});
|
|
|
|
|
2019-11-21 16:08:00 +03:00
|
|
|
afterEach(function () {
|
2019-06-18 16:13:55 +03:00
|
|
|
sandbox.restore();
|
2014-10-10 18:54:07 +04:00
|
|
|
});
|
|
|
|
|
2014-11-28 14:09:45 +03:00
|
|
|
it('returns meta tag plus injected code', function (done) {
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: {
|
|
|
|
post: false
|
|
|
|
},
|
|
|
|
locals: {
|
|
|
|
context: ['paged', 'index'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2014-10-10 18:54:07 +04:00
|
|
|
should.exist(rendered);
|
2020-06-30 17:07:08 +03:00
|
|
|
rendered.string.should.match(/<link rel="icon" href="\/favicon.png" type="image\/png" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
2015-02-05 16:06:36 +03:00
|
|
|
rendered.string.should.match(/<style>body {background: red;}<\/style>/);
|
2014-10-10 18:54:07 +04:00
|
|
|
|
2017-03-14 19:50:35 +03:00
|
|
|
// No default meta desc in paged context
|
|
|
|
rendered.string.should.not.match(/<meta name="description" \/>/);
|
|
|
|
|
2014-10-10 18:54:07 +04:00
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
|
2017-08-02 14:06:51 +03:00
|
|
|
it('outputs post codeinjection as well', function (done) {
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: {
|
|
|
|
post: {
|
|
|
|
codeinjection_head: 'post-codeinjection'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
locals: {
|
|
|
|
context: ['paged', 'index'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2017-08-02 12:38:19 +03:00
|
|
|
should.exist(rendered);
|
2017-08-02 14:06:51 +03:00
|
|
|
rendered.string.should.match(/<style>body {background: red;}<\/style>/);
|
2017-08-02 12:38:19 +03:00
|
|
|
rendered.string.should.match(/post-codeinjection/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('handles post codeinjection being empty', function (done) {
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: {
|
|
|
|
post: {
|
|
|
|
codeinjection_head: ''
|
|
|
|
}
|
|
|
|
},
|
|
|
|
locals: {
|
|
|
|
context: ['paged', 'index'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2017-08-02 12:38:19 +03:00
|
|
|
should.exist(rendered);
|
|
|
|
rendered.string.should.match(/<style>body {background: red;}<\/style>/);
|
|
|
|
rendered.string.should.not.match(/post-codeinjection/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('handles post codeinjection being null', function (done) {
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: {
|
|
|
|
post: {
|
|
|
|
codeinjection_head: null
|
|
|
|
}
|
|
|
|
},
|
|
|
|
locals: {
|
|
|
|
context: ['paged', 'index'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2017-08-02 12:38:19 +03:00
|
|
|
should.exist(rendered);
|
|
|
|
rendered.string.should.match(/<style>body {background: red;}<\/style>/);
|
|
|
|
rendered.string.should.not.match(/post-codeinjection/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
it('returns meta tag without injected code for amp context', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
post: posts[1]
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
};
|
2017-10-26 13:03:53 +03:00
|
|
|
|
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
context: ['amp', 'post'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
should.exist(rendered);
|
2020-06-30 17:07:08 +03:00
|
|
|
rendered.string.should.match(/<link rel="icon" href="\/favicon.png" type="image\/png" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="canonical" href="http:\/\/localhost:65530\/" \/>/);
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
2017-08-31 12:39:37 +03:00
|
|
|
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/localhost:65530\/rss\/" \/>/);
|
✨ [FEATURE] AMP⚡ (#7229)
closes #6588, #7095
* `ImageObject` with image dimensions (#7152, #7151, #7153)
- Returns meta data as promise
- returns a new Promise from meta data
- uses `Promise.props()` to resolve `getClient()` and `getMetaData()`
- Adds 'image-size' util
The util returns an object like this
```
{
height: 50,
url: 'http://myblog.com/images/cat.jpg',
width: 50
};
```
if the dimensions can be fetched and rejects with error, if not.
In case we get a locally stored image or a not complete url (like `//www.gravatar.com/andsoon`), we add the protocol to the incomplete one and use `urlFor()` to get the absolute URL. If the request fails or `image-size` is not able to read the file, we reject with error.
- adds 'image-size' module to dependencies
- adds `getImageSizeFromUrl` function that returns image dimensions
- In preparation of AMP support and to improve our schema.org JSON-LD and structured data, I made the following changes:
- Changes the following properties to be `Objects`, which have a `url` property by default and a `dimensions` property, if `width` and `height` are available:
- `metaData.coverImage`
- `metaData.authorImage`
- `metaData.blog.logo`
- Checks cache by calling `getCachedImageSizeFromUrl`. If image dimensions were fetched already, returns them from cache instead of fetching them again.
- If we have image dimensions on hand, the output in our JSON-LD changes from normal urls to be full `ImageObjects`. Applies to all images and logos.
- Special case for `publisher.logo` as it has size restrictions: if the image doesn't fulfil the restrictions (<=600 width and <=60 height), we simply output the url instead, so like before.
- Adds new property for schema.org JSON-LD: `mainEntityOfPage` as an Object.
- Adds additional Open Graph data (if we have the image size): `og:image:width` and `og:image:height`
- Adds/updates tests
* AMP router and controller (#7171, #7157)
Implements AMP in `/apps/`:
- renders `amp.hbs` if route is `/:slug/amp/`
- updates `setResponseContext` to set context to `['amp', 'post']` for a amp post and `['amp', 'page']` for a page, but will not render amp template for a page
- updates `context_spec`
- registers 'amp' as new internal app
- adds the `amp.hbs` template to `core/server/apps/amp` which will be the default template for AMP posts.
- adds `isAmpURL` to `post-lookup`
* 🎨 Use `context` in meta as array (#7205)
Instead of reading the first value of the context array, we're checking if it includes certain context values.
This is a preparation change for AMP, where the context will be delivered as `['amp', 'post']`.
* ✨ AMP helpers (#7174, #7216, #7215, #7223)
- Adds AMP helpers `{{amp_content}}`, `{{amp_component}}` and `{{amp_ghost_head}}` to support AMP:
- `{{amp_content}}`:
- Adds `Amperize` as dependency
- AMP app uses new helper `{{amp_content}}` to render AMP HTML
- `Amperize` transforms regular HTML into AMP HTML
- Adds test for `{{amp_content}}` helper
- Adds 'Sanitize-HTML` as dependendy
- After the HTML get 'amperized' we still might have some HTML tags, which are prohibited in AMP HTML, so we use `sanitize-html` to remove those. With every update, `Amperize` gets and it is able to transform more HTML tags, they valid AMP HTML tags (e. g. `video` and `amp-video`) and will therefore not be removed.
- `{{amp_ghost_head}}`:
- registers `{{amp_ghost_head}}` helper, but uses `{{ghost_head}}` code
- uses `{{amp_ghost_head}}` in `amp.hbs` instead of `{{ghost_head}}`
- `{{ghost_head}}`:
- Render `amphtml` link in metadata for post, which links to the amp post (`getAmpUrl`)
- Updates all test in metadata to support `amp` context
- Changes context conditionals to work with full array instead of first array value
- Adds conditionals, so no additional javascript gets rendered in `{{ghost_head}}`
- Removes trailing `/amp/` in URLs, so only `amphtml` link on regular post renders it
- Adds a conditional, so no code injection will be included, for an `amp` context.
- `{{amp_components}}`:
- AMP app uses new helper `{{amp_components}}` to render necessary script tags for AMP extended components as `amp-iframe`, `amp-anime` and `amp-form`
- Adds test for `{{amp_components}}`
2016-08-22 19:49:27 +03:00
|
|
|
rendered.string.should.not.match(/<style>body {background: red;}<\/style>/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
2014-10-10 18:54:07 +04:00
|
|
|
});
|
2015-11-11 07:33:19 +03:00
|
|
|
|
2017-01-17 18:40:06 +03:00
|
|
|
describe('amp is disabled', function () {
|
2019-11-21 16:08:00 +03:00
|
|
|
beforeEach(function () {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
settingsCache.get.withArgs('amp').returns(false);
|
2017-01-17 18:40:06 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
it('does not contain amphtml link', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const renderObject = {
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
post: posts[1]
|
2017-01-17 18:40:06 +03:00
|
|
|
};
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
|
2017-10-26 13:03:53 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/post/',
|
|
|
|
context: ['post'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
2017-01-17 18:40:06 +03:00
|
|
|
should.exist(rendered);
|
|
|
|
rendered.string.should.not.match(/<link rel="amphtml"/);
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
});
|
2021-03-02 14:40:45 +03:00
|
|
|
|
|
|
|
describe('accent_color', function () {
|
|
|
|
it('includes style tag when set', function (done) {
|
|
|
|
const renderObject = {
|
|
|
|
post: posts[1]
|
|
|
|
};
|
|
|
|
|
2021-03-03 11:00:41 +03:00
|
|
|
const templateOptions = {
|
|
|
|
site: {
|
|
|
|
accent_color: '#123456'
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-03-02 14:40:45 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
2021-03-03 11:00:41 +03:00
|
|
|
templateOptions,
|
2021-03-02 14:40:45 +03:00
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/post/',
|
|
|
|
context: ['post'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
|
|
|
should.exist(rendered);
|
2021-03-02 22:48:58 +03:00
|
|
|
rendered.string.should.containEql('<style>:root {--ghost-accent-color: #123456;}</style>');
|
2021-03-02 14:40:45 +03:00
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('does not include style tag when not set', function (done) {
|
|
|
|
const renderObject = {
|
|
|
|
post: posts[1]
|
|
|
|
};
|
|
|
|
|
2021-03-03 11:00:41 +03:00
|
|
|
const templateOptions = {
|
|
|
|
site: {
|
|
|
|
accent_color: null
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-03-02 14:40:45 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
2021-03-03 11:00:41 +03:00
|
|
|
templateOptions,
|
2021-03-02 14:40:45 +03:00
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/post/',
|
|
|
|
context: ['post'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
|
|
|
should.exist(rendered);
|
2021-03-02 22:48:58 +03:00
|
|
|
rendered.string.should.not.containEql('--ghost-accent-color');
|
2021-03-02 14:40:45 +03:00
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('attaches style tag to existing script/style tag', function (done) {
|
|
|
|
const renderObject = {
|
|
|
|
post: posts[1]
|
|
|
|
};
|
|
|
|
|
2021-03-03 11:00:41 +03:00
|
|
|
const templateOptions = {
|
|
|
|
site: {
|
|
|
|
accent_color: '#123456'
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-03-02 14:40:45 +03:00
|
|
|
helpers.ghost_head(testUtils.createHbsResponse({
|
2021-03-03 11:00:41 +03:00
|
|
|
templateOptions,
|
2021-03-02 14:40:45 +03:00
|
|
|
renderObject: renderObject,
|
|
|
|
locals: {
|
|
|
|
relativeUrl: '/post/',
|
|
|
|
context: ['post'],
|
|
|
|
safeVersion: '0.3'
|
|
|
|
}
|
|
|
|
})).then(function (rendered) {
|
|
|
|
should.exist(rendered);
|
|
|
|
rendered.string.should.match(/[^\s]<style>:root/);
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
});
|
2014-10-10 18:54:07 +04:00
|
|
|
});
|