From 1a73870e785c8e668a1e801bc680e1e73d7cd00f Mon Sep 17 00:00:00 2001 From: Goulven Champenois Date: Wed, 14 Nov 2018 14:00:09 +0100 Subject: [PATCH 1/4] Allow customising collection feed titles --- README.md | 9 +++++++++ lib/jekyll-feed/feed.xml | 14 +------------- lib/jekyll-feed/generator.rb | 26 +++++++++++++++++++++++--- spec/jekyll-feed_spec.rb | 25 +++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 518aced7..f9c4dee0 100644 --- a/README.md +++ b/README.md @@ -170,6 +170,15 @@ feed: path: "/changes.xml" ``` +Collection feed titles will include the capitalized collection name. If you'd like to customize the feed title, specify a collection's custom title as follows: + +```yml +feed: + collections: + changes: + title: "My collection title" +``` + Finally, collections can also have category feeds which are outputted as `/feed//.xml`. Specify categories like so: ```yml diff --git a/lib/jekyll-feed/feed.xml b/lib/jekyll-feed/feed.xml index 4d4fd16d..3c52b498 100644 --- a/lib/jekyll-feed/feed.xml +++ b/lib/jekyll-feed/feed.xml @@ -9,19 +9,7 @@ {{ site.time | date_to_xmlschema }} {{ page.url | absolute_url | xml_escape }} - {% assign title = site.title | default: site.name %} - {% if page.collection != "posts" %} - {% assign collection = page.collection | capitalize %} - {% assign title = title | append: " | " | append: collection %} - {% endif %} - {% if page.category %} - {% assign category = page.category | capitalize %} - {% assign title = title | append: " | " | append: category %} - {% endif %} - - {% if title %} - {{ title | smartify | xml_escape }} - {% endif %} + {{ page.feed_title | smartify | xml_escape }} {% if site.description %} {{ site.description | xml_escape }} diff --git a/lib/jekyll-feed/generator.rb b/lib/jekyll-feed/generator.rb index 13684056..865a3aa7 100644 --- a/lib/jekyll-feed/generator.rb +++ b/lib/jekyll-feed/generator.rb @@ -12,9 +12,10 @@ def generate(site) Jekyll.logger.info "Jekyll Feed:", "Generating feed for #{name}" (meta["categories"] + [nil]).each do |category| path = feed_path(:collection => name, :category => category) + feed_title = feed_title(:collection => name, :category => category) next if file_exists?(path) - @site.pages << make_page(path, :collection => name, :category => category) + @site.pages << make_page(path, feed_title, :collection => name, :category => category) end end end @@ -48,6 +49,24 @@ def feed_path(collection: "posts", category: nil) collections.dig(collection, "path") || "#{prefix}.xml" end + # Determines the title of a given feed + # + # collection - the name of a collection, e.g., "posts" + # category - a category within that collection, e.g., "news" + # + # Will return the site title or name + # ...followed by collection title or capitalized name + # ...followed by capitalized category name + def feed_title(collection: "posts", category: nil) + words = [] + words << (@site.config["title"] || @site.config["name"]) + unless collection == "posts" + words << (collections.dig(collection, "title") || collection.capitalize) + end + words << category.capitalize if category + words.compact.join " | " + end + # Returns a hash representing all collections to be processed and their metadata # in the form of { collection_name => { categories = [...], path = "..." } } def collections @@ -85,7 +104,7 @@ def file_exists?(file_path) # Generates contents for a file - def make_page(file_path, collection: "posts", category: nil) + def make_page(file_path, title, collection: "posts", category: nil) PageWithoutAFile.new(@site, __dir__, "", file_path).tap do |file| file.content = feed_template file.data.merge!( @@ -93,7 +112,8 @@ def make_page(file_path, collection: "posts", category: nil) "sitemap" => false, "xsl" => file_exists?("feed.xslt.xml"), "collection" => collection, - "category" => category + "category" => category, + "feed_title" => title ) file.output end diff --git a/spec/jekyll-feed_spec.rb b/spec/jekyll-feed_spec.rb index 9dce5cea..9d87786d 100644 --- a/spec/jekyll-feed_spec.rb +++ b/spec/jekyll-feed_spec.rb @@ -429,6 +429,31 @@ end end + context "with collection title" do + let(:collection_with_title_feed) { File.read(dest_dir("feed/collection_with_title.xml")) } + let(:overrides) do + { + "collections" => { + "collection_with_title" => { + "output" => true, + "path" => 'collection_with_title' + }, + }, + "feed" => { + "collections" => { + "collection_with_title" => { + "title" => "My collection title", + }, + }, + }, + } + end + + it "outputs the collection feed with custom title" do + expect(collection_with_title_feed).to match 'My Awesome Site | My collection title' + end + end + context "with categories" do let(:overrides) do { From 3e89e8d0e05fafd053be4aa21dcab0cb933e6b59 Mon Sep 17 00:00:00 2001 From: Goulven Champenois Date: Wed, 14 Nov 2018 15:35:40 +0100 Subject: [PATCH 2/4] Output feed links for collections --- README.md | 4 +++ lib/jekyll-feed/generator.rb | 28 ++++++++--------- lib/jekyll-feed/meta-tag.rb | 61 +++++++++++++++++++++++++++++++----- spec/jekyll-feed_spec.rb | 60 +++++++++++++++++++++++++++++++++++ 4 files changed, 131 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index f9c4dee0..69adaf49 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 865a3aa7..5ffefb00 100644 --- a/lib/jekyll-feed/generator.rb +++ b/lib/jekyll-feed/generator.rb @@ -20,19 +20,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" @@ -46,7 +33,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 # Determines the title of a given feed @@ -88,6 +75,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..d520127e 100644 --- a/lib/jekyll-feed/meta-tag.rb +++ b/lib/jekyll-feed/meta-tag.rb @@ -5,10 +5,26 @@ class MetaTag < Liquid::Tag # Use Jekyll's native relative_url filter include Jekyll::Filters::URLFilters + def initialize(tag_name, args, tokens) + super + @args = args + end + def render(context) @context = context - attrs = attributes.map { |k, v| %(#{k}="#{v}") }.join(" ") - "" + if @args.strip == "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 +33,50 @@ def config @config ||= @context.registers[:site].config end - def attributes + def generator + @generator ||= @context.registers[:site].generators.select { |it| it.is_a? JekyllFeed::Generator }.first # rubocop:disable Metrics/LineLength + 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 + + Jekyll.logger.warn( + "Jekyll Feed:", + "Invalid collection name. Please review `{% feed_meta #{@args} %}`" + ) + false + 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) + + Jekyll.logger.warn( + "Jekyll Feed:", + "Invalid category 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 9d87786d..42c667c4 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('') From 2246052348b74286b5b27895af73c3638ef56339 Mon Sep 17 00:00:00 2001 From: Goulven Champenois Date: Sat, 17 Nov 2018 19:36:06 +0100 Subject: [PATCH 3/4] Use collection title in collection feed links --- lib/jekyll-feed/meta-tag.rb | 7 ++----- spec/jekyll-feed_spec.rb | 8 ++++---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/jekyll-feed/meta-tag.rb b/lib/jekyll-feed/meta-tag.rb index d520127e..b0af940c 100644 --- a/lib/jekyll-feed/meta-tag.rb +++ b/lib/jekyll-feed/meta-tag.rb @@ -44,16 +44,13 @@ def link(collection, category) def attributes(collection, category) href = absolute_url(generator.feed_path(:collection => collection, :category => category)) + title = generator.feed_title(:collection => collection, :category => category) { :type => "application/atom+xml", :rel => "alternate", :href => href, :title => title, - }.keep_if { |_, v| v } - end - - def title - config["title"] || config["name"] + }.delete_if { |_, v| v.strip.empty? } end def valid_collection diff --git a/spec/jekyll-feed_spec.rb b/spec/jekyll-feed_spec.rb index 42c667c4..f2a31de5 100644 --- a/spec/jekyll-feed_spec.rb +++ b/spec/jekyll-feed_spec.rb @@ -349,8 +349,8 @@ it "renders the feed meta for the selected collection" do default_feed_link = '' - collection_feed_link = '' - category_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) @@ -378,8 +378,8 @@ it "renders the feed meta for all collections and categories" do default_feed_link = '' - collection_feed_link = '' - category_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) From 99c5ce4d1d4998099cab82106e21ed2be11020ec Mon Sep 17 00:00:00 2001 From: Ashwin Maroli Date: Wed, 6 Feb 2019 21:11:27 +0530 Subject: [PATCH 4/4] DRY repeated code with a private helper method --- lib/jekyll-feed/meta-tag.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/jekyll-feed/meta-tag.rb b/lib/jekyll-feed/meta-tag.rb index b0af940c..a1e42ad8 100644 --- a/lib/jekyll-feed/meta-tag.rb +++ b/lib/jekyll-feed/meta-tag.rb @@ -56,11 +56,7 @@ def attributes(collection, category) def valid_collection return true if generator.collections.key? @collection - Jekyll.logger.warn( - "Jekyll Feed:", - "Invalid collection name. Please review `{% feed_meta #{@args} %}`" - ) - false + invalidate_with_warning("collection") end def valid_category @@ -69,9 +65,13 @@ def valid_category 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 category name. Please review `{% feed_meta #{@args} %}`" + "Invalid #{type} name. Please review `{% feed_meta #{@args} %}`" ) false end