I use Middleman as static page genarator for this website. One question I often get is how to build separate Atom feed for every category/tag that I use on this site. Here is solution that I end up using almost a year ago.

Code that I placed at the end of config.rb file:

def get_tags(resource)
  if resource.data.tags.is_a? String
    resource.data.tags.split(',').map(&:strip)
  else
    resource.data.tags
  end
end

def group_lookup(resource, sum)
  results = Array(get_tags(resource)).map(&:to_s).map(&:to_sym)
  results.each do |k|
    sum[k] ||= []
    sum[k] << resource
  end
end

tags_for_feed = resources.select { |resource| resource.data.tags }.each_with_object({}, &method(:group_lookup))

require 'middleman-blog/uri_templates'
class Middleman::CoreExtensions::Collections::StepContext
  include Middleman::Blog::UriTemplates
end

tags_for_feed.each do |tag, articles|
  proxy "/articles/tags/#{safe_parameterize(tag)}/feed.xml", '/tag_feed.xml',
        layout: false, locals: { tagname: tag, articles: articles }
end

ignore '/tag_feed.xml'

And my sourcs/tag_feed.xml looks like this:

xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do
  site_url = data.site.url
  xml.title "Simplify - Articles tagged with #{tagname}"
  xml.subtitle data.site.description
  xml.id URI.join(site_url, tag_path(tagname))
  xml.link "href" => URI.join(site_url, tag_path(tagname))
  xml.link "href" => URI.join(site_url, current_page.path), "rel" => "self"
  xml.updated(blog.articles.first.date.to_time.iso8601) unless blog.articles.empty?
  xml.author { xml.name data.site.author }

  articles.sort_by {|a| a.date }.reverse.each do |article|
    xml.entry do
      xml.title article.title
      xml.link "rel" => "alternate", "href" => URI.join(site_url, article.url)
      xml.id URI.join(site_url, article.url)
      xml.published article.date.to_time.iso8601
      xml.updated File.mtime(article.source_file).iso8601
      xml.author { xml.name data.site.author }
      xml.content article.body, "type" => "html"
    end
  end
end
Share on: