lib/jekyll-feed/generator.rb in jekyll-feed-0.10.0 vs lib/jekyll-feed/generator.rb in jekyll-feed-0.11.0

- old
+ new

@@ -6,52 +6,106 @@ priority :lowest # Main plugin action, called by Jekyll-core def generate(site) @site = site - return if file_exists?(feed_path) - @site.pages << content_for_file(feed_path, feed_source_path) + 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 end private # Matches all whitespace that follows # 1. A '>', which closes an XML tag or # 2. A '}', which closes a Liquid tag # We will strip all of this whitespace to minify the template MINIFY_REGEX = %r!(?<=>|})\s+! - # Path to feed from config, or feed.xml for default - def feed_path - if @site.config["feed"] && @site.config["feed"]["path"] - @site.config["feed"]["path"] - else - "feed.xml" + # Returns the plugin's config or an empty hash if not set + def config + @config ||= @site.config["feed"] || {} + end + + # Determines the destination path of a given feed + # + # collection - the name of a collection, e.g., "posts" + # category - a category within that collection, e.g., "news" + # + # Will return "/feed.xml", or the config-specified default feed for posts + # Will return `/feed/category.xml` for post categories + # WIll return `/feed/collection.xml` for other collections + # Will return `/feed/collection/category.xml` for other collection categories + 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 + + # Returns a hash representing all collections to be processed and their metadata + # in the form of { collection_name => { categories = [...], path = "..." } } + def collections + return @collections if defined?(@collections) + + @collections = if config["collections"].is_a?(Array) + config["collections"].map { |c| [c, {}] }.to_h + elsif config["collections"].is_a?(Hash) + config["collections"] + else + {} + end + + @collections = normalize_posts_meta(@collections) + @collections.each_value do |meta| + meta["categories"] = (meta["categories"] || []).to_set end + + @collections end # Path to feed.xml template file def feed_source_path - File.expand_path "feed.xml", __dir__ + @feed_source_path ||= File.expand_path "feed.xml", __dir__ end + def feed_template + @feed_template ||= File.read(feed_source_path).gsub(MINIFY_REGEX, "") + end + # Checks if a file already exists in the site source def file_exists?(file_path) - if @site.respond_to?(:in_source_dir) - File.exist? @site.in_source_dir(file_path) - else - File.exist? Jekyll.sanitized_path(@site.source, file_path) - end + File.exist? @site.in_source_dir(file_path) end # Generates contents for a file - def content_for_file(file_path, file_source_path) - file = PageWithoutAFile.new(@site, __dir__, "", file_path) - file.content = File.read(file_source_path).gsub(MINIFY_REGEX, "") - file.data["layout"] = nil - file.data["sitemap"] = false - file.data["xsl"] = file_exists?("feed.xslt.xml") - file.output - file + + def make_page(file_path, collection: "posts", category: 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 + ) + file.output + end + end + + # Special case the "posts" collection, which, for ease of use and backwards + # compatability, can be configured via top-level keys or directly as a collection + def normalize_posts_meta(hash) + hash["posts"] ||= {} + hash["posts"]["path"] ||= config["path"] + hash["posts"]["categories"] ||= config["categories"] + config["path"] ||= hash["posts"]["path"] + hash end end end