diff --git a/core/server/services/routing/CollectionRouter.js b/core/server/services/routing/CollectionRouter.js index 541ebd6356..942fc25c23 100644 --- a/core/server/services/routing/CollectionRouter.js +++ b/core/server/services/routing/CollectionRouter.js @@ -28,6 +28,9 @@ class CollectionRouter extends ParentRouter { this.templates = (object.templates || []).reverse(); this.filter = object.filter || 'page:false'; + this.data = object.data || {query: {}, router: {}}; + this.order = object.order; + this.limit = object.limit; /** * @deprecated Remove in Ghost 2.0 @@ -92,13 +95,16 @@ class CollectionRouter extends ParentRouter { _prepareEntriesContext(req, res, next) { res.locals.routerOptions = { filter: this.filter, + limit: this.limit, + order: this.order, permalinks: this.permalinks.getValue({withUrlOptions: true}), type: this.getType(), context: this.context, frontPageTemplate: 'home', templates: this.templates, identifier: this.identifier, - name: this.routerName + name: this.routerName, + data: this.data.query }; res._route = { diff --git a/core/server/services/routing/controllers/collection.js b/core/server/services/routing/controllers/collection.js index 48f5ebd49c..6b3643392d 100644 --- a/core/server/services/routing/controllers/collection.js +++ b/core/server/services/routing/controllers/collection.js @@ -15,11 +15,24 @@ module.exports = function collectionController(req, res, next) { }; if (pathOptions.page) { - const postsPerPage = parseInt(themes.getActive().config('posts_per_page')); + // CASE 1: routes.yaml `limit` is stronger than theme definition + // CASE 2: use `posts_per_page` config from theme as `limit` value + if (res.locals.routerOptions.limit) { + themes.getActive().updateTemplateOptions({ + data: { + config: { + posts_per_page: res.locals.routerOptions.limit + } + } + }); - // CASE: no negative posts per page - if (!isNaN(postsPerPage) && postsPerPage > 0) { - pathOptions.limit = postsPerPage; + pathOptions.limit = res.locals.routerOptions.limit; + } else { + const postsPerPage = parseInt(themes.getActive().config('posts_per_page')); + + if (!isNaN(postsPerPage) && postsPerPage > 0) { + pathOptions.limit = postsPerPage; + } } } diff --git a/core/server/services/routing/helpers/fetch-data.js b/core/server/services/routing/helpers/fetch-data.js index 9c15e8caee..1031fa0e91 100644 --- a/core/server/services/routing/helpers/fetch-data.js +++ b/core/server/services/routing/helpers/fetch-data.js @@ -68,6 +68,10 @@ function fetchData(pathOptions, routerOptions) { postQuery.options.filter = routerOptions.filter; } + if (routerOptions.order) { + postQuery.options.order = routerOptions.order; + } + if (pathOptions.hasOwnProperty('page')) { postQuery.options.page = pathOptions.page; } diff --git a/core/server/services/themes/active.js b/core/server/services/themes/active.js index 67e6242fe0..4570a016f1 100644 --- a/core/server/services/themes/active.js +++ b/core/server/services/themes/active.js @@ -12,6 +12,7 @@ * */ var join = require('path').join, + _ = require('lodash'), themeConfig = require('./config'), config = require('../../config'), engine = require('./engine'), @@ -74,6 +75,10 @@ class ActiveTheme { return this._templates.indexOf(templateName) > -1; } + updateTemplateOptions(options) { + engine._options.templateOptions = _.merge(engine._options.templateOptions, options); + } + config(key) { return this._config[key]; } diff --git a/core/test/unit/services/routing/CollectionRouter_spec.js b/core/test/unit/services/routing/CollectionRouter_spec.js index f7624f8505..23d2d4f507 100644 --- a/core/test/unit/services/routing/CollectionRouter_spec.js +++ b/core/test/unit/services/routing/CollectionRouter_spec.js @@ -155,12 +155,15 @@ describe('UNIT - services/routing/CollectionRouter', function () { identifier: collectionRouter.identifier, context: ['index'], name: 'index', - type: 'posts' + type: 'posts', + data: {}, + order: undefined, + limit: undefined }); }); - it('with templates, no index collection', function () { - const collectionRouter = new CollectionRouter('/magic/', {permalink: '/:slug/', templates: ['home', 'index']}); + it('with templates, with order + limit, no index collection', function () { + const collectionRouter = new CollectionRouter('/magic/', {permalink: '/:slug/', order: 'published asc', limit: 19, templates: ['home', 'index']}); collectionRouter._prepareEntriesContext(req, res, next); @@ -173,7 +176,10 @@ describe('UNIT - services/routing/CollectionRouter', function () { identifier: collectionRouter.identifier, context: ['magic'], name: 'magic', - type: 'posts' + type: 'posts', + data: {}, + order: 'published asc', + limit: 19 }); }); }); diff --git a/core/test/unit/services/routing/controllers/collection_spec.js b/core/test/unit/services/routing/controllers/collection_spec.js index 14da68710e..092ff94507 100644 --- a/core/test/unit/services/routing/controllers/collection_spec.js +++ b/core/test/unit/services/routing/controllers/collection_spec.js @@ -42,6 +42,7 @@ describe('Unit - services/routing/controllers/collection', function () { }); sandbox.stub(themeService, 'getActive').returns({ + updateTemplateOptions: sandbox.stub(), config: function (key) { key.should.eql('posts_per_page'); return postsPerPage; @@ -125,6 +126,36 @@ describe('Unit - services/routing/controllers/collection', function () { controllers.collection(req, res, failTest(done)); }); + it('update hbs engine: router defines limit', function (done) { + res.locals.routerOptions.limit = 3; + req.params.page = 2; + + fetchDataStub.withArgs({page: 2, slug: undefined, limit: 3}, res.locals.routerOptions) + .resolves({ + posts: posts, + meta: { + pagination: { + pages: 3 + } + } + }); + + filters.doFilter.withArgs('prePostsRender', posts, res.locals).resolves(); + + renderStub.callsFake(function () { + themeService.getActive.calledOnce.should.be.true(); + themeService.getActive().updateTemplateOptions.withArgs({data: {config: {posts_per_page: 3}}}).calledOnce.should.be.true(); + security.string.safe.calledOnce.should.be.false(); + fetchDataStub.calledOnce.should.be.true(); + filters.doFilter.calledOnce.should.be.true(); + secureStub.calledOnce.should.be.true(); + urlService.owns.calledOnce.should.be.true(); + done(); + }); + + controllers.collection(req, res, failTest(done)); + }); + it('page param too big', function (done) { req.params.page = 6;