0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-13 22:41:32 -05:00
ghost/core/server/data/sitemap/base-generator.js
Jacob Gable ef16c67a15 Sort newest to oldest in sitemap files
Closes #4611

Refactored generateXmlFromNodes to pull the urlElements itself from
sorted values in the lookup

Added some checks to existing unit tests to validate ordering.
2014-12-09 12:41:31 -08:00

203 lines
5.8 KiB
JavaScript

var _ = require('lodash'),
xml = require('xml'),
moment = require('moment'),
api = require('../../api'),
config = require('../../config'),
utils = require('./utils'),
Promise = require('bluebird'),
CHANGE_FREQ = 'weekly',
XMLNS_DECLS;
// Sitemap specific xml namespace declarations that should not change
XMLNS_DECLS = {
_attr: {
xmlns: 'http://www.sitemaps.org/schemas/sitemap/0.9',
'xmlns:image': 'http://www.google.com/schemas/sitemap-image/1.1'
}
};
function BaseSiteMapGenerator() {
this.lastModified = 0;
this.nodeLookup = {};
this.nodeTimeLookup = {};
this.siteMapContent = '';
}
_.extend(BaseSiteMapGenerator.prototype, {
init: function () {
return this.refreshAll();
},
getData: function () {
return Promise.resolve([]);
},
refreshAll: function () {
var self = this;
// Load all data
return this.getData().then(function (data) {
// Generate SiteMap from data
return self.generateXmlFromData(data);
}).then(function (generatedXml) {
self.siteMapContent = generatedXml;
});
},
generateXmlFromData: function (data) {
// This has to be async because of the permalinks retrieval
var self = this;
// Fetch the permalinks value only once for all the urlFor calls
return this.getPermalinksValue().then(function (permalinks) {
// Create all the url elements in JSON
return _.map(data, function (datum) {
var node = self.createUrlNodeFromDatum(datum, permalinks);
self.updateLastModified(datum);
self.updateLookups(datum, node);
return node;
});
}).then(this.generateXmlFromNodes.bind(this));
},
getPermalinksValue: function () {
var self = this;
if (this.permalinks) {
return Promise.resolve(this.permalinks);
}
return api.settings.read('permalinks').then(function (response) {
self.permalinks = response.settings[0];
return self.permalinks;
});
},
updatePermalinksValue: function (permalinks) {
this.permalinks = permalinks;
// Re-generate xml with new permalinks values
this.updateXmlFromNodes();
},
generateXmlFromNodes: function () {
var self = this,
// Get a mapping of node to timestamp
timedNodes = _.map(this.nodeLookup, function (node, id) {
return {
id: id,
// Using negative here to sort newest to oldest
ts: -(self.nodeTimeLookup[id] || 0),
node: node
};
}, []),
// Sort nodes by timestamp
sortedNodes = _.sortBy(timedNodes, 'ts'),
// Grab just the nodes
urlElements = _.pluck(sortedNodes, 'node'),
data = {
// Concat the elements to the _attr declaration
urlset: [XMLNS_DECLS].concat(urlElements)
};
// Return the xml
return utils.getDeclarations() + xml(data);
},
updateXmlFromNodes: function (urlElements) {
var content = this.generateXmlFromNodes(urlElements);
this.setSiteMapContent(content);
return content;
},
addUrl: function (datum) {
var self = this;
return this.getPermalinksValue().then(function (permalinks) {
var node = self.createUrlNodeFromDatum(datum, permalinks);
self.updateLastModified(datum);
self.updateLookups(datum, node);
return self.updateXmlFromNodes();
});
},
removeUrl: function (datum) {
this.removeFromLookups(datum);
this.lastModified = Date.now();
return this.updateXmlFromNodes();
},
updateUrl: function (datum) {
var self = this;
return this.getPermalinksValue().then(function (permalinks) {
var node = self.createUrlNodeFromDatum(datum, permalinks);
self.updateLastModified(datum);
// TODO: Check if the node values changed, and if not don't regenerate
self.updateLookups(datum, node);
return self.updateXmlFromNodes();
});
},
getUrlForDatum: function () {
return config.urlFor('home', true);
},
getUrlForImage: function (image) {
return config.urlFor('image', {image: image}, true);
},
getPriorityForDatum: function () {
return 1.0;
},
getLastModifiedForDatum: function (datum) {
return datum.updated_at || datum.published_at || datum.created_at;
},
createUrlNodeFromDatum: function (datum, permalinks) {
var url = this.getUrlForDatum(datum, permalinks),
priority = this.getPriorityForDatum(datum);
return {
url: [
{loc: url},
{lastmod: moment(this.getLastModifiedForDatum(datum)).toISOString()},
{changefreq: CHANGE_FREQ},
{priority: priority}
]
};
},
setSiteMapContent: function (content) {
this.siteMapContent = content;
},
updateLastModified: function (datum) {
var lastModified = this.getLastModifiedForDatum(datum);
if (lastModified > this.lastModified) {
this.lastModified = lastModified;
}
},
updateLookups: function (datum, node) {
this.nodeLookup[datum.id] = node;
this.nodeTimeLookup[datum.id] = this.getLastModifiedForDatum(datum);
},
removeFromLookups: function (datum) {
var lookup = this.nodeLookup;
delete lookup[datum.id];
lookup = this.nodeTimeLookup;
delete lookup[datum.id];
}
});
module.exports = BaseSiteMapGenerator;