From c3c8aab94a61e60b712d9df5be5cb8168e978d72 Mon Sep 17 00:00:00 2001 From: Charlie DeTar Date: Fri, 12 Dec 2014 11:03:23 -0700 Subject: [PATCH] Update SEO package for master, remove page titles --- packages/telescope-seo/.gitignore | 1 + packages/telescope-seo/package.js | 24 +++ packages/telescope-seo/seo.js | 190 +++++++++++++++++++++ packages/telescope-seo/versions.json | 239 +++++++++++++++++++++++++++ 4 files changed, 454 insertions(+) create mode 100644 packages/telescope-seo/.gitignore create mode 100644 packages/telescope-seo/package.js create mode 100644 packages/telescope-seo/seo.js create mode 100644 packages/telescope-seo/versions.json diff --git a/packages/telescope-seo/.gitignore b/packages/telescope-seo/.gitignore new file mode 100644 index 000000000..677a6fc26 --- /dev/null +++ b/packages/telescope-seo/.gitignore @@ -0,0 +1 @@ +.build* diff --git a/packages/telescope-seo/package.js b/packages/telescope-seo/package.js new file mode 100644 index 000000000..ce74a54f4 --- /dev/null +++ b/packages/telescope-seo/package.js @@ -0,0 +1,24 @@ +Package.describe({ + name: "telescope-seo", + summary: "SEO extensions for Telescope", + version: "0.0.3" +}); + +Package.onUse(function(api) { + + api.use([ + "underscore", + "aldeed:simple-schema", + "iron:router", + "telescope-lib", + "telescope-base", + "telescope-tags", + "manuelschoebel:ms-seo@0.4.1", + "gadicohen:sitemaps@0.0.20" + ]); + + api.export([ + ]); + + api.addFiles("seo.js", ['client', 'server']); +}); diff --git a/packages/telescope-seo/seo.js b/packages/telescope-seo/seo.js new file mode 100644 index 000000000..c98115268 --- /dev/null +++ b/packages/telescope-seo/seo.js @@ -0,0 +1,190 @@ +// 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; + }); + } + }); +} diff --git a/packages/telescope-seo/versions.json b/packages/telescope-seo/versions.json new file mode 100644 index 000000000..963d1fcc0 --- /dev/null +++ b/packages/telescope-seo/versions.json @@ -0,0 +1,239 @@ +{ + "dependencies": [ + [ + "aldeed:simple-schema", + "1.1.0" + ], + [ + "application-configuration", + "1.0.3" + ], + [ + "base64", + "1.0.1" + ], + [ + "binary-heap", + "1.0.1" + ], + [ + "blaze", + "2.0.3" + ], + [ + "blaze-tools", + "1.0.1" + ], + [ + "boilerplate-generator", + "1.0.1" + ], + [ + "callback-hook", + "1.0.1" + ], + [ + "check", + "1.0.2" + ], + [ + "coffeescript", + "1.0.4" + ], + [ + "ddp", + "1.0.12" + ], + [ + "deps", + "1.0.5" + ], + [ + "ejson", + "1.0.4" + ], + [ + "follower-livedata", + "1.0.2" + ], + [ + "gadicohen:robots-txt", + "0.0.8" + ], + [ + "gadicohen:sitemaps", + "0.0.20" + ], + [ + "geojson-utils", + "1.0.1" + ], + [ + "html-tools", + "1.0.2" + ], + [ + "htmljs", + "1.0.2" + ], + [ + "id-map", + "1.0.1" + ], + [ + "iron:controller", + "1.0.3" + ], + [ + "iron:core", + "1.0.3" + ], + [ + "iron:dynamic-template", + "1.0.3" + ], + [ + "iron:layout", + "1.0.3" + ], + [ + "iron:location", + "1.0.3" + ], + [ + "iron:middleware-stack", + "1.0.3" + ], + [ + "iron:router", + "1.0.3" + ], + [ + "iron:url", + "1.0.3" + ], + [ + "jquery", + "1.0.1" + ], + [ + "json", + "1.0.1" + ], + [ + "logging", + "1.0.5" + ], + [ + "manuelschoebel:ms-seo", + "0.4.1" + ], + [ + "meteor", + "1.1.3" + ], + [ + "minifiers", + "1.1.2" + ], + [ + "minimongo", + "1.0.5" + ], + [ + "mongo", + "1.0.9" + ], + [ + "observe-sequence", + "1.0.3" + ], + [ + "ordered-dict", + "1.0.1" + ], + [ + "random", + "1.0.1" + ], + [ + "reactive-dict", + "1.0.4" + ], + [ + "reactive-var", + "1.0.3" + ], + [ + "retry", + "1.0.1" + ], + [ + "routepolicy", + "1.0.2" + ], + [ + "session", + "1.0.4" + ], + [ + "spacebars", + "1.0.3" + ], + [ + "spacebars-compiler", + "1.0.3" + ], + [ + "tap:http-methods", + "0.0.23" + ], + [ + "tap:i18n", + "1.2.1" + ], + [ + "telescope-base", + "0.0.0" + ], + [ + "telescope-i18n", + "0.0.0" + ], + [ + "telescope-lib", + "0.2.9" + ], + [ + "telescope-tags", + "0.0.0" + ], + [ + "templating", + "1.0.9" + ], + [ + "tracker", + "1.0.3" + ], + [ + "ui", + "1.0.4" + ], + [ + "underscore", + "1.0.1" + ], + [ + "webapp", + "1.1.4" + ], + [ + "webapp-hashing", + "1.0.1" + ] + ], + "pluginDependencies": [], + "toolVersion": "meteor-tool@1.0.36", + "format": "1.0" +} \ No newline at end of file