Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create JSON feed #173

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
5 changes: 3 additions & 2 deletions 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)

Expand All @@ -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

Expand All @@ -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.
Expand Down
77 changes: 77 additions & 0 deletions lib/jekyll-feed/feed.json
@@ -0,0 +1,77 @@
{
"version": "https://jsonfeed.org/version/1",
{% assign site_title = site.title | site.name %}
{% if site_title %}
"title": {{ site_title | smartify | json }},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i can't find json filter there https://jekyllrb.com/docs/templates/ may be jsonify

{% endif %}
{% if site.description %}
"description": {{ site.description | json }},
{% endif %}
"home_page_url": "{{ '/' | absolute_url }}",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why just not {{ absolute_url }}?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

absolute_url is a filter not a value. It needs something as input.

"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 }},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think content_html should have a full content of post

"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": [

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"tags": {{ post.tags | jsonify }},

{% for tag in post.tags %}
{{ tag | json }}
{% unless forloop.last %},{% endunless %}
{% endfor %}
]
}
{% unless forloop.last %},{% endunless %}
{% endfor %}
]
}
41 changes: 37 additions & 4 deletions lib/jekyll-feed/generator.rb
Expand Up @@ -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
Expand All @@ -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__)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File.expand_path("feed.xml", __dir__)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The feed_source_path function used that same format and I just changed the file path. Please note that I don't know any Ruby and I might be wrong.

end

# Checks if a file already exists in the site source
def file_exists?(file_path)
if @site.respond_to?(:in_source_dir)
Expand All @@ -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