diff --git a/README.md b/README.md index 518aced7..fc335b6c 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,10 @@ There are several ways to convey author-specific information. Author information The plugin exposes a helper tag to expose the appropriate meta tags to support automated discovery of your feed. Simply place `{% feed_meta %}` someplace in your template's `
` section, to output the necessary metadata. +The helper can also generate the link for a given collection: `{% feed_meta my_collection %}` or a given category: `{% feed_meta my_collection my_category %}`. + +To generate links for every collections and categories, call the helper using this syntax: `{% feed_meta include: all %}`. + ### SmartyPants The plugin uses [Jekyll's `smartify` filter](https://jekyllrb.com/docs/templates/) for processing the site title and post titles. This will translate plain ASCII punctuation into "smart" typographic punctuation. This will not render or strip any Markdown you may be using in a title. diff --git a/lib/jekyll-feed/generator.rb b/lib/jekyll-feed/generator.rb index 13684056..3fd11c6a 100644 --- a/lib/jekyll-feed/generator.rb +++ b/lib/jekyll-feed/generator.rb @@ -19,19 +19,6 @@ def generate(site) 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+!.freeze - - # 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" @@ -45,7 +32,7 @@ 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" + @collections.dig(collection, "path") || "#{prefix}.xml" end # Returns a hash representing all collections to be processed and their metadata @@ -69,6 +56,19 @@ def collections @collections 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+!.freeze + + # Returns the plugin's config or an empty hash if not set + def config + @config ||= @site.config["feed"] || {} + end + # Path to feed.xml template file def feed_source_path @feed_source_path ||= File.expand_path "feed.xml", __dir__ diff --git a/lib/jekyll-feed/meta-tag.rb b/lib/jekyll-feed/meta-tag.rb index 76da23f0..5456225b 100644 --- a/lib/jekyll-feed/meta-tag.rb +++ b/lib/jekyll-feed/meta-tag.rb @@ -5,10 +5,29 @@ class MetaTag < Liquid::Tag # Use Jekyll's native relative_url filter include Jekyll::Filters::URLFilters + def initialize(tag_name, args, tokens) + super + @args = args.strip + end + def render(context) @context = context - attrs = attributes.map { |k, v| %(#{k}="#{v}") }.join(" ") - "" + @collection = nil + @category = nil + + if @args == "include: all" + links = [] + generator.collections.each do |collection, meta| + (meta["categories"] + [nil]).each do |category| + links << link(collection, category) + end + end + links.reverse.join "\n" + else + @collection, @category = @args.split(" ") + @collection ||= "posts" + link(@collection, @category) if valid_collection && valid_category + end end private @@ -17,21 +36,52 @@ def config @config ||= @context.registers[:site].config end - def attributes + def generator + @generator ||= @context.registers[:site].generators.find do |generator| + generator.is_a? JekyllFeed::Generator + end + end + + def link(collection, category) + attrs = attributes(collection, category).map { |k, v| %(#{k}="#{v}") }.join(" ") + "" + end + + def attributes(collection, category) + href = absolute_url(generator.feed_path(:collection => collection, :category => category)) { :type => "application/atom+xml", :rel => "alternate", - :href => absolute_url(path), + :href => href, :title => title, }.keep_if { |_, v| v } end - def path - config.dig("feed", "path") || "feed.xml" - end - def title config["title"] || config["name"] end + + def valid_collection + return true if generator.collections.key? @collection + + invalidate_with_warning("collection") + end + + def valid_category + return true if @collection == "posts" || @category.nil? + + collection = generator.collections[@collection] + return true if collection.key?("categories") && collection["categories"].include?(@category) + + invalidate_with_warning("category") + end + + def invalidate_with_warning(type) + Jekyll.logger.warn( + "Jekyll Feed:", + "Invalid #{type} name. Please review `{% feed_meta #{@args} %}`" + ) + false + end end end diff --git a/spec/jekyll-feed_spec.rb b/spec/jekyll-feed_spec.rb index 9dce5cea..72d9730f 100644 --- a/spec/jekyll-feed_spec.rb +++ b/spec/jekyll-feed_spec.rb @@ -326,6 +326,66 @@ end end + context "selecting a particular collection" do + let(:overrides) do + { + "collections" => { + "collection" => { + "output" => true, + }, + }, + "feed" => { + "collections" => { + "collection" => { + "categories" => ["news"], + }, + }, + }, + } + end + let(:default_feed) { Liquid::Template.parse("{% feed_meta posts %}").render!(context, {}) } + let(:collection_feed) { Liquid::Template.parse("{% feed_meta collection %}").render!(context, {}) } + let(:category_feed) { Liquid::Template.parse("{% feed_meta collection news %}").render!(context, {}) } + + it "renders the feed meta for the selected collection" do + default_feed_link = '' + collection_feed_link = '' + category_feed_link = '' + expect(default_feed).to eql(default_feed_link) + expect(collection_feed).to eql(collection_feed_link) + expect(category_feed).to eql(category_feed_link) + end + end + + context "requesting all feed links" do + let(:overrides) do + { + "collections" => { + "collection" => { + "output" => true, + }, + }, + "feed" => { + "collections" => { + "collection" => { + "categories" => ["news"], + }, + }, + }, + } + end + let(:full_feed_meta) { Liquid::Template.parse("{% feed_meta include: all %}").render!(context, {}) } + + it "renders the feed meta for all collections and categories" do + default_feed_link = '' + collection_feed_link = '' + category_feed_link = '' + expect(full_feed_meta).to include(default_feed_link) + expect(full_feed_meta).to include(collection_feed_link) + expect(full_feed_meta).to include(category_feed_link) + end + end + context "feed stylesheet" do it "includes the stylesheet" do expect(contents).to include('')