mirror of
https://github.com/vale981/Vulcan
synced 2025-03-10 12:36:39 -04:00
Refactor for getDescription and package style
Update package style to accord with the example of ``packages/telescope-blank``. Add i18n. Simplify description setting into a single setting for both meta descriptions and og:description. Use ``getTitle`` and ``getDescription``.
This commit is contained in:
parent
46b7a3af34
commit
d17c447561
11 changed files with 184 additions and 202 deletions
|
@ -79,3 +79,5 @@ useraccounts:unstyled@1.4.0
|
||||||
|
|
||||||
telescope-datetimepicker
|
telescope-datetimepicker
|
||||||
tsega:bootstrap3-datetimepicker@3.1.3_1
|
tsega:bootstrap3-datetimepicker@3.1.3_1
|
||||||
|
telescope-seo
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,8 @@ facebook@1.1.2
|
||||||
fastclick@1.0.1
|
fastclick@1.0.1
|
||||||
follower-livedata@1.0.2
|
follower-livedata@1.0.2
|
||||||
fourseven:scss@1.0.0
|
fourseven:scss@1.0.0
|
||||||
|
gadicohen:robots-txt@0.0.8
|
||||||
|
gadicohen:sitemaps@0.0.20
|
||||||
geojson-utils@1.0.1
|
geojson-utils@1.0.1
|
||||||
handlebars@1.0.1
|
handlebars@1.0.1
|
||||||
html-tools@1.0.2
|
html-tools@1.0.2
|
||||||
|
@ -62,6 +64,7 @@ less@1.0.11
|
||||||
livedata@1.0.11
|
livedata@1.0.11
|
||||||
localstorage@1.0.1
|
localstorage@1.0.1
|
||||||
logging@1.0.5
|
logging@1.0.5
|
||||||
|
manuelschoebel:ms-seo@0.4.1
|
||||||
matb33:collection-hooks@0.7.6
|
matb33:collection-hooks@0.7.6
|
||||||
meteor-platform@1.2.0
|
meteor-platform@1.2.0
|
||||||
meteor@1.1.3
|
meteor@1.1.3
|
||||||
|
@ -125,6 +128,7 @@ telescope-newsletter@0.1.0
|
||||||
telescope-notifications@0.1.0
|
telescope-notifications@0.1.0
|
||||||
telescope-rss@0.0.0
|
telescope-rss@0.0.0
|
||||||
telescope-search@0.0.0
|
telescope-search@0.0.0
|
||||||
|
telescope-seo@0.0.4
|
||||||
telescope-singleday@0.1.0
|
telescope-singleday@0.1.0
|
||||||
telescope-tags@0.0.0
|
telescope-tags@0.0.0
|
||||||
telescope-theme-base@0.0.0
|
telescope-theme-base@0.0.0
|
||||||
|
|
6
packages/telescope-seo/i18n/en.i18n.json
Normal file
6
packages/telescope-seo/i18n/en.i18n.json
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"search_engine_optimization": "search engine optimization",
|
||||||
|
"seoDescription": "meta and og description",
|
||||||
|
"seoOgImage": "og:image",
|
||||||
|
"seoGenerateSitemap": "Generate Sitemap (requires restart)"
|
||||||
|
}
|
53
packages/telescope-seo/lib/routes.js
Normal file
53
packages/telescope-seo/lib/routes.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
Meteor.startup(function() {
|
||||||
|
var addSeoTags = function(descriptionFn, canonicalUrlFn) {
|
||||||
|
var props = {link: {}, meta: {}, og: {}};
|
||||||
|
var title = this.getTitle && this.getTitle();
|
||||||
|
var description = descriptionFn.call(this);
|
||||||
|
var image = getSetting("seoOgImage");
|
||||||
|
if (title) {
|
||||||
|
props.og.title = title;
|
||||||
|
}
|
||||||
|
if (description) {
|
||||||
|
props.meta.description = description;
|
||||||
|
props.og.description = description;
|
||||||
|
}
|
||||||
|
if (image) {
|
||||||
|
props.og.image = image;
|
||||||
|
}
|
||||||
|
if (canonicalUrlFn) {
|
||||||
|
props.link.canonical = canonicalUrlFn.call(this);
|
||||||
|
}
|
||||||
|
SEO.set(props);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Front page: prefer description from settings over this.getDescription.
|
||||||
|
var frontPageDescription = function() {
|
||||||
|
return getSetting("seoDescription") || (this.getDescription && this.getDescription());
|
||||||
|
};
|
||||||
|
|
||||||
|
// All others: prefer this.getDescription over settings.
|
||||||
|
var notFrontPageDescription = function() {
|
||||||
|
return (this.getDescription && this.getDescription()) || getSetting("seoDescription");
|
||||||
|
};
|
||||||
|
|
||||||
|
var frontPage = ["posts_" + getSetting("frontPage", "top").toLowerCase()];
|
||||||
|
var postPage = ["post_page", "post_page_with_slug"];
|
||||||
|
|
||||||
|
// Front page
|
||||||
|
Router.onAfterAction(function() {
|
||||||
|
addSeoTags.call(this, frontPageDescription);
|
||||||
|
}, {only: frontPage});
|
||||||
|
|
||||||
|
// Post detail pages
|
||||||
|
Router.onAfterAction(function() {
|
||||||
|
addSeoTags.call(this, notFrontPageDescription, function getCanonicalUrl() {
|
||||||
|
var post = Posts.findOne(this.params._id);
|
||||||
|
return getPostPageUrl(post);
|
||||||
|
});
|
||||||
|
}, {only: postPage});
|
||||||
|
|
||||||
|
// All others
|
||||||
|
Router.onAfterAction(function() {
|
||||||
|
addSeoTags.call(this, notFrontPageDescription);
|
||||||
|
}, {except: frontPage.concat(postPage)});
|
||||||
|
});
|
39
packages/telescope-seo/lib/seo.js
Normal file
39
packages/telescope-seo/lib/seo.js
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
// Add SEO settings.
|
||||||
|
addToSettingsSchema.push({
|
||||||
|
propertyName: "seoDescription",
|
||||||
|
propertySchema: {
|
||||||
|
type: String,
|
||||||
|
optional: true,
|
||||||
|
label: "description",
|
||||||
|
autoform: {
|
||||||
|
group: "search engine optimization",
|
||||||
|
instructions: "Content for the meta description og:description tags for the front page and others that don't otherwise specify it.",
|
||||||
|
rows: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
addToSettingsSchema.push({
|
||||||
|
propertyName: "seoOgImage",
|
||||||
|
propertySchema: {
|
||||||
|
type: String,
|
||||||
|
optional: true,
|
||||||
|
regEx: SimpleSchema.RegEx.Url,
|
||||||
|
label: "og:image",
|
||||||
|
autoform: {
|
||||||
|
group: "search engine optimization",
|
||||||
|
instructions: "URL to an image for the open graph image tag for all pages"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
addToSettingsSchema.push({
|
||||||
|
propertyName: "seoGenerateSitemap",
|
||||||
|
propertySchema: {
|
||||||
|
type: Boolean,
|
||||||
|
defaultValue: false,
|
||||||
|
label: "Generate sitemap",
|
||||||
|
autoform: {
|
||||||
|
group: "search engine optimization",
|
||||||
|
instructions: "Automatically generate an XML sitemap for search engines, and append the sitemap URL to the output of robots.txt? NOTE: Requires restart to reflect change."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
58
packages/telescope-seo/lib/server/sitemaps.js
Normal file
58
packages/telescope-seo/lib/server/sitemaps.js
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
Meteor.startup(function() {
|
||||||
|
/*
|
||||||
|
* Sitemap
|
||||||
|
*/
|
||||||
|
if (getSetting("seoGenerateSitemap")) {
|
||||||
|
sitemaps.add("/sitemap.xml", function() {
|
||||||
|
var _getLatest = function(viewParamKey, terms) {
|
||||||
|
var params = getPostsParameters(
|
||||||
|
viewParameters[viewParamKey.toLowerCase()](terms)
|
||||||
|
);
|
||||||
|
var post = Posts.findOne(params.find, {
|
||||||
|
'fields': {'postedAt': 1},
|
||||||
|
'sort': params.options.sort
|
||||||
|
});
|
||||||
|
return post ? post.postedAt : null;
|
||||||
|
}
|
||||||
|
// Posts list pages
|
||||||
|
var paths = [
|
||||||
|
{page: "/", lastmod: _getLatest(getSetting("defaultView", "top")), changefreq: "hourly"},
|
||||||
|
{page: "/top", lastmod: _getLatest("top"), changefreq: "hourly"},
|
||||||
|
{page: "/new", lastmod: _getLatest("new"), changefreq: "hourly"},
|
||||||
|
{page: "/best", lastmod: _getLatest("best"), changefreq: "daily"},
|
||||||
|
];
|
||||||
|
// Categories (if telescope-tags is included)
|
||||||
|
if (typeof Categories !== "undefined") {
|
||||||
|
Categories.find({}, {fields: {"slug": 1}}).forEach(function(category) {
|
||||||
|
var lastMod = _getLatest("category", {category: category.slug});
|
||||||
|
if (lastMod) {
|
||||||
|
paths.push({
|
||||||
|
page: "/category/" + category.slug,
|
||||||
|
lastmod: lastMod,
|
||||||
|
changefreq: "hourly"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Individual post pages: include 100 latest in each of "top", "new", and
|
||||||
|
// "best". Aggregate them to avoid duplication.
|
||||||
|
var postPages = {};
|
||||||
|
_.each(["top", "new", "best"], function(key) {
|
||||||
|
var siteUrl = getSiteUrl();
|
||||||
|
var params = getPostsParameters(viewParameters[key]());
|
||||||
|
var posts = Posts.find(params.find, {
|
||||||
|
fields: {postedAt: 1, title: 1, _id: 1},
|
||||||
|
limit: 100,
|
||||||
|
sort: params.options.sort
|
||||||
|
});
|
||||||
|
posts.forEach(function(post) {
|
||||||
|
var url = getPostPageUrl(post).replace(siteUrl, "");
|
||||||
|
postPages[url] = {page: url, lastmod: post.postedAt, changefreq: "daily"};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
paths = paths.concat(_.values(postPages));
|
||||||
|
paths = _.reject(paths, function(p) { return p.lastmod === null });
|
||||||
|
return paths;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
5
packages/telescope-seo/package-tap.i18n
Normal file
5
packages/telescope-seo/package-tap.i18n
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"translation_function_name": "__",
|
||||||
|
"helper_name": "_",
|
||||||
|
"namespace": "project"
|
||||||
|
}
|
|
@ -1,24 +1,32 @@
|
||||||
Package.describe({
|
Package.describe({
|
||||||
name: "telescope-seo",
|
name: "telescope-seo",
|
||||||
summary: "SEO extensions for Telescope",
|
summary: "SEO extensions for Telescope",
|
||||||
version: "0.0.3"
|
version: "0.0.4"
|
||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
|
|
||||||
api.use([
|
api.use([
|
||||||
|
"templating",
|
||||||
"underscore",
|
"underscore",
|
||||||
"aldeed:simple-schema",
|
"aldeed:simple-schema",
|
||||||
|
"tap:i18n",
|
||||||
"iron:router",
|
"iron:router",
|
||||||
"telescope-lib",
|
"telescope-lib",
|
||||||
"telescope-base",
|
"telescope-base",
|
||||||
"telescope-tags",
|
"telescope-i18n",
|
||||||
"manuelschoebel:ms-seo@0.4.1",
|
"manuelschoebel:ms-seo@0.4.1",
|
||||||
"gadicohen:sitemaps@0.0.20"
|
"gadicohen:sitemaps@0.0.20"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
api.export([
|
// both
|
||||||
]);
|
api.addFiles([
|
||||||
|
"lib/routes.js",
|
||||||
|
"lib/seo.js",
|
||||||
|
"package-tap.i18n"
|
||||||
|
], ['client', 'server']);
|
||||||
|
|
||||||
api.addFiles("seo.js", ['client', 'server']);
|
// server
|
||||||
|
api.addFiles([
|
||||||
|
"lib/server/sitemaps.js"
|
||||||
|
], ["server"]);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,190 +0,0 @@
|
||||||
// Add SEO settings.
|
|
||||||
addToSettingsSchema.push({
|
|
||||||
propertyName: "seoMetaDescription",
|
|
||||||
propertySchema: {
|
|
||||||
type: String,
|
|
||||||
optional: true,
|
|
||||||
label: "meta description",
|
|
||||||
autoform: {
|
|
||||||
group: "search engine optimization",
|
|
||||||
instructions: "Content for the meta description tag for the front page and others that don't otherwise specify it.",
|
|
||||||
rows: 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
addToSettingsSchema.push({
|
|
||||||
propertyName: "seoOgDescription",
|
|
||||||
propertySchema: {
|
|
||||||
type: String,
|
|
||||||
optional: true,
|
|
||||||
label: "og:description",
|
|
||||||
autoform: {
|
|
||||||
group: "search engine optimization",
|
|
||||||
instructions: "Content for the open graph description tag for the front page and others that don't otherwise specify it.",
|
|
||||||
rows: 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
addToSettingsSchema.push({
|
|
||||||
propertyName: "seoOgImage",
|
|
||||||
propertySchema: {
|
|
||||||
type: String,
|
|
||||||
optional: true,
|
|
||||||
regEx: SimpleSchema.RegEx.Url,
|
|
||||||
label: "og:image",
|
|
||||||
autoform: {
|
|
||||||
group: "search engine optimization",
|
|
||||||
instructions: "URL to an image for the open graph image tag for all pages"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
addToSettingsSchema.push({
|
|
||||||
propertyName: "seoGenerateSitemap",
|
|
||||||
propertySchema: {
|
|
||||||
type: Boolean,
|
|
||||||
defaultValue: false,
|
|
||||||
label: "Generate sitemap",
|
|
||||||
autoform: {
|
|
||||||
group: "search engine optimization",
|
|
||||||
instructions: "Automatically generate an XML sitemap for search engines, and append the sitemap URL to the output of robots.txt? NOTE: Requires restart to reflect change."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (Meteor.isClient) {
|
|
||||||
Meteor.startup(function() {
|
|
||||||
/*
|
|
||||||
* Meta tags
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Post pages
|
|
||||||
Router.onAfterAction(function() {
|
|
||||||
var post = Posts.findOne(this.params._id);
|
|
||||||
if (!post) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var title = (typeof this.getTitle === 'function') ? this.getTitle() : post.title;
|
|
||||||
if (post.categories && post.categories.length > 0) {
|
|
||||||
title += " - " + _.pluck(post.categories, "name").join(", ");
|
|
||||||
}
|
|
||||||
var stitle = getSetting("title");
|
|
||||||
if (stitle) {
|
|
||||||
title += " - " + stitle;
|
|
||||||
}
|
|
||||||
var description = [getSetting("tagline"), post.title].join(" ");
|
|
||||||
SEO.set({
|
|
||||||
link: { canonical: getPostPageUrl(post) },
|
|
||||||
meta: { description: description },
|
|
||||||
og: {
|
|
||||||
title: title,
|
|
||||||
description: description,
|
|
||||||
image: getSetting("seoOgImage")
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, {only: ["post_page", "post_page_with_slug"]});
|
|
||||||
|
|
||||||
// User pages
|
|
||||||
Router.onAfterAction(function() {
|
|
||||||
var user = Meteor.users.findOne(this.params._idOrSlug);
|
|
||||||
if (user) {
|
|
||||||
var title;
|
|
||||||
if (typeof this.getTitle === 'function') {
|
|
||||||
title = this.getTitle();
|
|
||||||
} else {
|
|
||||||
title = getUserName(user) + " - " + getSetting("title", "");
|
|
||||||
}
|
|
||||||
var description = "User profile for " + getUserName(user) + " - " + getSetting("title");
|
|
||||||
SEO.set({
|
|
||||||
link: { canonical: getSiteUrl() + "users/" + user._id },
|
|
||||||
meta: { description: description },
|
|
||||||
og: {
|
|
||||||
title: title,
|
|
||||||
description: description,
|
|
||||||
image: getSetting("seoOgImage")
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, {only: ["user_profile"]});
|
|
||||||
|
|
||||||
// All other pages
|
|
||||||
Router.onAfterAction(function() {
|
|
||||||
var title;
|
|
||||||
if (typeof this.getTitle === 'function') {
|
|
||||||
title = this.getTitle();
|
|
||||||
} else {
|
|
||||||
var stitle = getSetting("title");
|
|
||||||
var stagline = getSetting("tagline");
|
|
||||||
title = (stagline ? stitle + ": " + stagline : stitle) || "";
|
|
||||||
}
|
|
||||||
SEO.set({
|
|
||||||
meta: {description: getSetting("seoMetaDescription")},
|
|
||||||
og: {
|
|
||||||
title: title,
|
|
||||||
description: getSetting("seoOgDescription"),
|
|
||||||
image: getSetting("seoOgImage")
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, {except: ["user_profile", "post_page", "post_page_with_slug"]});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Meteor.isServer) {
|
|
||||||
Meteor.startup(function() {
|
|
||||||
/*
|
|
||||||
* Sitemap
|
|
||||||
*/
|
|
||||||
if (getSetting("seoGenerateSitemap")) {
|
|
||||||
sitemaps.add("/sitemap.xml", function() {
|
|
||||||
var _getLatest = function(viewParamKey, terms) {
|
|
||||||
var params = getPostsParameters(
|
|
||||||
viewParameters[viewParamKey.toLowerCase()](terms)
|
|
||||||
);
|
|
||||||
var post = Posts.findOne(params.find, {
|
|
||||||
'fields': {'postedAt': 1},
|
|
||||||
'sort': params.options.sort
|
|
||||||
});
|
|
||||||
return post ? post.postedAt : null;
|
|
||||||
}
|
|
||||||
// Posts list pages
|
|
||||||
var paths = [
|
|
||||||
{page: "/", lastmod: _getLatest(getSetting("defaultView", "top")), changefreq: "hourly"},
|
|
||||||
{page: "/top", lastmod: _getLatest("top"), changefreq: "hourly"},
|
|
||||||
{page: "/new", lastmod: _getLatest("new"), changefreq: "hourly"},
|
|
||||||
{page: "/best", lastmod: _getLatest("best"), changefreq: "daily"},
|
|
||||||
];
|
|
||||||
// Categories (if telescope-tags is included)
|
|
||||||
if (typeof Categories !== "undefined") {
|
|
||||||
Categories.find({}, {fields: {"slug": 1}}).forEach(function(category) {
|
|
||||||
var lastMod = _getLatest("category", {category: category.slug});
|
|
||||||
if (lastMod) {
|
|
||||||
paths.push({
|
|
||||||
page: "/category/" + category.slug,
|
|
||||||
lastmod: lastMod,
|
|
||||||
changefreq: "hourly"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Individual post pages: include 100 latest in each of "top", "new", and
|
|
||||||
// "best". Aggregate them to avoid duplication.
|
|
||||||
var postPages = {};
|
|
||||||
_.each(["top", "new", "best"], function(key) {
|
|
||||||
var siteUrl = getSiteUrl();
|
|
||||||
var params = getPostsParameters(viewParameters[key]());
|
|
||||||
var posts = Posts.find(params.find, {
|
|
||||||
fields: {postedAt: 1, title: 1, _id: 1},
|
|
||||||
limit: 100,
|
|
||||||
sort: params.options.sort
|
|
||||||
});
|
|
||||||
posts.forEach(function(post) {
|
|
||||||
var url = getPostPageUrl(post).replace(siteUrl, "");
|
|
||||||
postPages[url] = {page: url, lastmod: post.postedAt, changefreq: "daily"};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
paths = paths.concat(_.values(postPages));
|
|
||||||
paths = _.reject(paths, function(p) { return p.lastmod === null });
|
|
||||||
return paths;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -204,10 +204,6 @@
|
||||||
"telescope-lib",
|
"telescope-lib",
|
||||||
"0.2.9"
|
"0.2.9"
|
||||||
],
|
],
|
||||||
[
|
|
||||||
"telescope-tags",
|
|
||||||
"0.0.0"
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
"templating",
|
"templating",
|
||||||
"1.0.9"
|
"1.0.9"
|
||||||
|
|
|
@ -411,8 +411,9 @@ var migrationsList = {
|
||||||
i++;
|
i++;
|
||||||
console.log("Post: " + post._id);
|
console.log("Post: " + post._id);
|
||||||
var justCategoryIds = post.categories.map(function (category){
|
var justCategoryIds = post.categories.map(function (category){
|
||||||
return category._id;
|
return category && category._id;
|
||||||
});
|
});
|
||||||
|
justCategoryIds = _.reject(justCategoryIds, function(id) { return id === null; });
|
||||||
var result = Posts.update(post._id, {$set: {categories: justCategoryIds, oldCategories: post.categories}}, {multi: true, validate: false});
|
var result = Posts.update(post._id, {$set: {categories: justCategoryIds, oldCategories: post.categories}}, {multi: true, validate: false});
|
||||||
console.log("---------------------");
|
console.log("---------------------");
|
||||||
});
|
});
|
||||||
|
@ -430,4 +431,4 @@ var migrationsList = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: normalize categories?
|
// TODO: normalize categories?
|
||||||
|
|
Loading…
Add table
Reference in a new issue