Skip to content

Commit

Permalink
Categories and collections (#228)
Browse files Browse the repository at this point in the history
Merge pull request 228
  • Loading branch information
benbalter authored and jekyllbot committed Sep 6, 2018
1 parent 3b71b7e commit b85ef9a
Show file tree
Hide file tree
Showing 9 changed files with 314 additions and 26 deletions.
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,48 @@ Want to style what your feed looks like in the browser? Simply add an XSLT at `/

Great question. In short, Atom is a better format. Think of it like RSS 3.0. For more information, see [this discussion on why we chose Atom over RSS 2.0](https://github.com/jekyll/jekyll-rss-feed/issues/2).

## Categories

Jekyll Feed can generate feeds for each category. Simply define which categories you'd like feeds for in your config:

```yml
feed:
categories:
- news
- updates
```

## Collections

Jekyll Feed can generate feeds for collections other than the Posts collection. This works best for chronological collections (e.g., collections with dates in the filenames). Simply define which collections you'd like feeds for in your config:

```yml
feed:
collections:
- changes
```

By default, collection feeds will be outputted to `/feed/<COLLECTION>.xml`. If you'd like to customize the output path, specify a collection's custom path as follows:

```yml
feed:
collections:
changes:
path: "/changes.xml"
```

Finally, collections can also have category feeds which are outputted as `/feed/<COLLECTION>/<CATEGORY>.xml`. Specify categories like so:

```yml
feed:
collections:
changes:
path: "/changes.xml"
categories:
- news
- updates
```

## Contributing

1. Fork it (https://github.com/jekyll/jekyll-feed/fork)
Expand Down
23 changes: 17 additions & 6 deletions lib/jekyll-feed/feed.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,20 @@
<link href="{{ page.url | absolute_url }}" rel="self" type="application/atom+xml" />
<link href="{{ '/' | absolute_url }}" rel="alternate" type="text/html" {% if site.lang %}hreflang="{{ site.lang }}" {% endif %}/>
<updated>{{ site.time | date_to_xmlschema }}</updated>
<id>{{ '/' | absolute_url | xml_escape }}</id>
<id>{{ page.url | absolute_url | xml_escape }}</id>

{% if site.title %}
<title type="html">{{ site.title | smartify | xml_escape }}</title>
{% elsif site.name %}
<title type="html">{{ site.name | smartify | xml_escape }}</title>
{% 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 type="html">{{ title | smartify | xml_escape }}</title>
{% endif %}

{% if site.description %}
Expand All @@ -31,7 +39,10 @@
</author>
{% endif %}

{% assign posts = site.posts | where_exp: "post", "post.draft != true" %}
{% assign posts = site[page.collection] | where_exp: "post", "post.draft != true" | sort: "date" | reverse %}
{% if page.category %}
{% assign posts = posts | where: "category",page.category %}
{% endif %}
{% for post in posts limit: 10 %}
<entry{% if post.lang %}{{" "}}xml:lang="{{ post.lang }}"{% endif %}>
<title type="html">{{ post.title | smartify | strip_html | normalize_whitespace | xml_escape }}</title>
Expand Down
88 changes: 75 additions & 13 deletions lib/jekyll-feed/generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@ class Generator < Jekyll::Generator
# 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
Expand All @@ -20,18 +26,59 @@ def generate(site)
# 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"]
# Returns the plugin's config or an empty hash if not set
def 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}"
if category
"#{prefix}/#{category}.xml"
elsif collections[collection] && collections[collection]["path"]
collections[collection]["path"]
else
"feed.xml"
"#{prefix}.xml"
end
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 do |_name, 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
Expand All @@ -44,14 +91,29 @@ def file_exists?(file_path)
end

# Generates contents for a file
def content_for_file(file_path, file_source_path)

def make_page(file_path, collection: "posts", category: nil)
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.content = feed_template
file.data.merge!({
"layout" => nil,
"sitemap" => false,
"xsl" => file_exists?("feed.xslt.xml"),
"collection" => collection,
"category" => category,
})
file.output
file
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
4 changes: 4 additions & 0 deletions spec/fixtures/_collection/2018-01-01-collection-doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
---

Look at me! I'm a collection!
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
category: news
---

Look at me! I'm a collection doc in a category!
1 change: 1 addition & 0 deletions spec/fixtures/_posts/2013-12-12-dec-the-second.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
excerpt: "Foo"
image: "/image.png"
category: news
---

# December the twelfth, actually.
1 change: 1 addition & 0 deletions spec/fixtures/_posts/2014-03-02-march-the-second.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
image: https://cdn.example.org/absolute.png?h=188&w=250
category: news
---

March the second!
1 change: 1 addition & 0 deletions spec/fixtures/_posts/2014-03-04-march-the-fourth.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ tags:
- '"/><VADER>'
image:
path: "/object-image.png"
category: updates
---

March the fourth!
Loading

0 comments on commit b85ef9a

Please sign in to comment.