// 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?"
    }
  }
})

if (Meteor.isClient) {
  Meteor.startup(function() {
    /*
     * Meta tags
     */

    // Post pages
    Router.onAfterAction(function() {
      var post = this.post();
      var title = 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({
        title: title,
        link: { canonical: getPostPageUrl(this.post()) },
        meta: { description: description },
        og: {
          title: title,
          description: description,
          image: getSetting("seo.og.image")
        }
      });
    }, {only: ["post_page", "post_page_with_slug"]});

    // User pages
    Router.onAfterAction(function() {
      var user = Meteor.users.findOne(this.params._idOrSlug);
      if (user) {
        var title = getUserName(user) + " - " + getSetting("title", "");
        var description = "User profile for " + getUserName(user) + " on " + getSetting("title");
        SEO.set({
          title: title,
          link: { canonical: getSiteUrl() + "users/" + user._id },
          meta: { description: description },
          og: {
            title: title,
            description: description,
            image: getSetting("seo.og.image")
          }
        });
      }
    }, {only: ["user_profile"]});

    // All other pages
    Router.onAfterAction(function() {
      var stitle = getSetting("title");
      var stagline = getSetting("tagline");
      var title = (stagline ? stitle + ": " + stagline : stitle) || "";
      SEO.set({
        title: title,
        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
     */
    console.log("Do generate sitemap", getSetting("seoGenerateSitemap"));
    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 });
        console.log("sitemap paths:", paths);
        return paths;
      });
    }
  });
}

@@ -1424,18 +1424,61 @@
 ots.txt?
+  NOTE: Requires restart to reflect change.
 %22%0A
-
     %7D%0A  
@@ -3623,82 +3623,8 @@
  */%0A
-    console.log(%22Do generate sitemap%22, getSetting(%22seoGenerateSitemap%22));%0A
     
@@ -5737,24 +5737,24 @@
 ostPages));%0A
+
         path
@@ -5821,54 +5821,8 @@
 %7D);%0A
-        console.log(%22sitemap paths:%22, paths);%0A
     

Document that changes to sitemap require restart.