diff --git a/README.md b/README.md index ed75c2b2..9c3ef6b8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Jekyll Feed plugin -A Jekyll plugin to generate an Atom (RSS-like) feed of your Jekyll posts +A Jekyll plugin to generate an Atom (RSS-like) feed and a [JSON feed](https://jsonfeed.org/version/1) of your Jekyll posts [![Build Status](https://travis-ci.org/jekyll/jekyll-feed.svg)](https://travis-ci.org/jekyll/jekyll-feed) [![Gem Version](https://badge.fury.io/rb/jekyll-feed.svg)](https://badge.fury.io/rb/jekyll-feed) @@ -21,7 +21,7 @@ gems: ## Usage -The plugin will automatically generate an Atom feed at `/feed.xml`. +The plugin will automatically generate an Atom feed at `/feed.xml` and a [JSON feed](https://jsonfeed.org/) at `/feed.json`. ### Optional configuration options @@ -39,6 +39,7 @@ Do you already have an existing feed someplace other than `/feed.xml`, but are o ```yml feed: path: atom.xml + json_path: json_feed.json ``` To note, you shouldn't have to do this unless you already have a feed you're using, and you can't or wish not to redirect existing subscribers. diff --git a/lib/jekyll-feed/feed.json b/lib/jekyll-feed/feed.json new file mode 100644 index 00000000..c8a51a0c --- /dev/null +++ b/lib/jekyll-feed/feed.json @@ -0,0 +1,72 @@ +{ + "version": "https://jsonfeed.org/version/1", + {% assign site_title = site.title | site.name %} + {% if site_title %} + "title": {{ site_title | smartify | json }}, + {% endif %} + {% if site.description %} + "description": {{ site.description | json }}, + {% endif %} + "home_page_url": "{{ '/' | absolute_url }}", + "feed_url": "{{ page.url | absolute_url }}", + "icon": "{{ "/apple-touch-icon.png" | absolute_url }}", + "favicon": "{{ "/favicon.ico" | absolute_url }}", + "expired": false, + {% if site.author %} + "author": { + "name": {{ site.author.name | default: site.author | json }}, + {% if site.author.uri %} + "url": {{ site.author.uri | json }} + {% endif %} + }, + {% endif %} + "items": [ + {% assign posts = site.posts | where_exp: "post", "post.draft != true" %} + {% for post in posts limit: 10 %} + { + "id": {{ post.id | absolute_url | json }}, + "url": "{{ post.url | absolute_url }}", + "title": {{ post.title | smartify | strip_html | normalize_whitespace | json }}, + {% if post.excerpt and post.excerpt != empty %} + {% assign post_summary = post.excerpt | strip_html | normalize_whitespace | json %} + "content_html": {{ post_summary }}, + "summary": {{ post_summary }}, + {% endif %} + {% assign post_image = post.image.path | default: post.image %} + {% if post_image %} + {% unless post_image contains "://" %} + {% assign post_image = post_image | absolute_url | xml_escape %} + {% endunless %} + "image": "{{ post_image }}", + {% endif %} + "date_published": "{{ post.date | date_to_xmlschema }}", + "date_modified": "{{ post.last_modified_at | default: post.date | date_to_xmlschema }}", + {% assign post_author = post.author | default: post.authors[0] %} + {% if post_author %} + {% assign post_author = site.data.authors[post_author] | default: post_author %} + {% assign post_author_uri = post_author.uri | default: nil %} + {% assign post_author_name = post_author.name | default: post_author %} + "author": { + {% if post_author_name %} + "name": {{ post_author_name | json }}, + {% endif %} + {% if post_author_uri %} + "url": {{ post_author_uri | json }} + {% endif %} + }, + {% endif %} + {% if post.enclosure %} + "attachments": [ + { + "url": "{{ post.enclosure }}", + "mime_type": "{{ post.enclosure_type }}", + "size_in_bytes": "{{ post.enclosure_length }}" + } + ], + {% endif %} + "tags": {{ post.tags | jsonify }} + } + {% unless forloop.last %},{% endunless %} + {% endfor %} + ] +} diff --git a/lib/jekyll-feed/generator.rb b/lib/jekyll-feed/generator.rb index 0ff34ed7..e46f4ba7 100644 --- a/lib/jekyll-feed/generator.rb +++ b/lib/jekyll-feed/generator.rb @@ -6,8 +6,10 @@ 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) + + return if file_exists?(feed_path) && file_exists?(json_feed_path) + @site.pages << xml_content_for_file(feed_path, feed_source_path) + @site.pages << json_content_for_file(json_feed_path, feed_json_source_path) end private @@ -27,11 +29,25 @@ def feed_path end end + # Path to JSON feed from config, or feed.json for default + def json_feed_path + if @site.config["feed"] && @site.config["feed"]["json_path"] + @site.config["feed"]["json_path"] + else + "feed.json" + end + end + # Path to feed.xml template file def feed_source_path File.expand_path "./feed.xml", File.dirname(__FILE__) end + # Path to feed.json template file + def feed_json_source_path + File.expand_path "./feed.json", File.dirname(__FILE__) + end + # Checks if a file already exists in the site source def file_exists?(file_path) if @site.respond_to?(:in_source_dir) @@ -42,14 +58,31 @@ def file_exists?(file_path) end # Generates contents for a file - def content_for_file(file_path, file_source_path) + def content_for_file(file_path, file_source_path, regex) file = PageWithoutAFile.new(@site, File.dirname(__FILE__), "", file_path) - file.content = File.read(file_source_path).gsub(MINIFY_REGEX, "") + content = File.read(file_source_path) + + if regex + content = content.gsub(regex, "") + end + + file.content = content file.data["layout"] = nil file.data["sitemap"] = false + file + end + + def xml_content_for_file(file_path, file_source_path) + file = content_for_file(file_path, file_source_path, MINIFY_REGEX) file.data["xsl"] = file_exists?("feed.xslt.xml") file.output file end + + def json_content_for_file(file_path, file_source_path) + file = content_for_file(file_path, file_source_path, nil) + file.output + file + end end end