class JekyllFeed::Generator
def collections
Returns a hash representing all collections to be processed and their metadata
def collections return @collections if defined?(@collections) @collections = case config["collections"] when Array config["collections"].map { |c| [c, {}] }.to_h when Hash config["collections"] else {} end @collections = normalize_posts_meta(@collections) @collections.each_value do |meta| meta["categories"] = (meta["categories"] || []).to_set end @collections end
def config
def config @config ||= @site.config["feed"] || {} end
def disabled_in_development?
def disabled_in_development? config && config["disable_in_development"] && Jekyll.env == "development" end
def feed_path(collection: "posts", category: nil)
WIll return `/feed/collection.xml` for other collections
Will return `/feed/category.xml` for post categories
Will return "/feed.xml", or the config-specified default feed for posts
category - a category within that collection, e.g., "news"
collection - the name of a collection, e.g., "posts"
Determines the destination path of a given feed
def feed_path(collection: "posts", category: nil) prefix = collection == "posts" ? "/feed" : "/feed/#{collection}" return "#{prefix}/#{category}.xml" if category collections.dig(collection, "path") || "#{prefix}.xml" end
def feed_source_path
def feed_source_path @feed_source_path ||= File.expand_path "feed.xml", __dir__ end
def feed_template
def feed_template @feed_template ||= File.read(feed_source_path).gsub(MINIFY_REGEX, "") end
def file_exists?(file_path)
def file_exists?(file_path) File.exist? @site.in_source_dir(file_path) end
def generate(site)
def generate(site) @site = site if disabled_in_development? Jekyll.logger.info "Jekyll Feed:", "Skipping feed generation in development" return end collections.each do |name, meta| Jekyll.logger.info "Jekyll Feed:", "Generating feed for #{name}" (meta["categories"] + [nil]).each do |category| path = feed_path(:collection => name, :category => category) next if file_exists?(path) @site.pages << make_page(path, :collection => name, :category => category) end end generate_feed_by_tag if config["tags"] && !@site.tags.empty? end
def generate_feed_by_tag
def generate_feed_by_tag tags_config = config["tags"] tags_config = {} unless tags_config.is_a?(Hash) except = tags_config["except"] || [] only = tags_config["only"] || @site.tags.keys tags_pool = only - except tags_path = tags_config["path"] || "/feed/by_tag/" generate_tag_feed(tags_pool, tags_path) end
def generate_tag_feed(tags_pool, tags_path)
def generate_tag_feed(tags_pool, tags_path) tags_pool.each do |tag| # allow only tags with basic alphanumeric characters and underscore to keep # feed path simple. next if %r![^a-zA-Z0-9_]!.match?(tag) Jekyll.logger.info "Jekyll Feed:", "Generating feed for posts tagged #{tag}" path = "#{tags_path}#{tag}.xml" next if file_exists?(path) @site.pages << make_page(path, :tags => tag) end end
def make_page(file_path, collection: "posts", category: nil, tags: nil)
def make_page(file_path, collection: "posts", category: nil, tags: nil) PageWithoutAFile.new(@site, __dir__, "", file_path).tap do |file| file.content = feed_template file.data.merge!( "layout" => nil, "sitemap" => false, "xsl" => file_exists?("feed.xslt.xml"), "collection" => collection, "category" => category, "tags" => tags ) file.output end end
def normalize_posts_meta(hash)
Special case the "posts" collection, which, for ease of use and backwards
def normalize_posts_meta(hash) hash["posts"] ||= {} hash["posts"]["path"] ||= config["path"] hash["posts"]["categories"] ||= config["categories"] config["path"] ||= hash["posts"]["path"] hash end