Alright, I was able to get it done with no real blocking issues. It could use improvement from someone better at ruby-fu than me, as it reads the configuration file for every post instead of looping just once. I’m writing up how to install it here, because I like this editor… but it’ll be mirrored at the:
So you want some discourse powered comments on your static site?
Well, good! This plugin combines javascript loaded on the page with a Liquid tag, written for jekyll to generate posts from your jekyll site, and then load the “best” comments from your discourse install. This is based on wp-discourse by sam. The only thing you have to bring to the table is some fancy CSS, as every jekyll site is different. Comments are created with IDs of “post#” starting at 1. Comments need to live in a div with an ID of “comments.”
Great! Let's go!
Now hold on for just a second. One of the big limitations of javascript is that it can not just pull data from another domain/subdomain. To have comments that update after your site is generated, we need to have something load them. So, we have to use one of two work-arounds to get past this. Our first option is to simply add a header to every response your server sends, permitting javscript to simply load across this restriction. However, the downsides to this are that you have to change settings with nginx/apache.
Your other option is to collect, with server-side code the responses we need. The major downside to this is you will have to allow non-static code to run where your static jekyll site lives. Kind of defeats the point in some ways. This part will be documented some time soon and is a valid way if the headers are not working out. If you’ve configured PHP, this is a script that will accomplish what’s needed. You’ll need to convert just the javascript request to be URL encoded.
For the first approach, follow the steps below. The second approach will require an edit to the javascript, and those directions will be at the bottom.
Preparing Discourse
You’ll need your API key handy (found in the admin section), and may want to create a category where posts will live. We next need to add a line of configuration to your config for nginx. The install guide leads you to create it in conf.d/discourse.conf.
add_header "Access-Control-Allow-Origin" "*";
This allows all sites to load your content via javascript. If you would like, replace the * with the public location of your jekyll install, including http://. The security of this is debated all over, but I find it safe. For more security, add the header only to your json files using a location block!
Preparing Octopress
This plugin requires httparty, a cool gem that makes HTTP requests easy. It also requires json, which is likely installed. We’ll double check by adding it anyway. To install it, simply remove your Gemfile.lock, and to your Gemfile add the lines below, and run a bundle install. You can’t just use gem install to do it.
gem 'httparty'
gem 'json'
Preparing Jekyll
*If you didn't install httparty and json above, do it here with:*
gem install httparty json
You’ll need the plugin files. Using some cool git submodules, we can add them in where needed and you can update on demand. For octopress, these are the paths, assuming you are in your octopress folder.
git submodule add https://github.com/trident523/jekyll-DiscourseBestOf.git plugins/discourse
git submodule add https://github.com/trident523/js-discourseBestOf.git source/javascripts/js
For just jekyll:
git submodule add https://github.com/trident523/jekyll-DiscourseBestOf.git _plugins/discourse
git submodule add https://github.com/trident523/js-discourseBestOf.git javascripts/js
Now, if you want the latest version just run git submodule update. Easier than it used to be! Remember when updating that the javascript file will need the correct URL.
Next, we need to add the liquid tag to one of your layouts. Edit _layouts/post.html to include
<script type="text/javascript" src="javascripts/js/js-discourse.js"></script>
<div id="comments" {% discourse_comments %}></div>
When the pages are created, this will add an attribute to the div tag called “tid”, which holds the related topic ID. We’re also loading the script right before it. This should probably be moved to your header instead, but for now let’s keep moving.
Back out of your source directory, and create a directory called _discourse. Next, edit your _config.yml to include:
discourse_api_key: Your api key
discourse_api_username: Username to post as
discourse_api_category: Category to post to
discourse_api_url: The URL of your discourse install, include http:// and no trailing slash.
Remember that spacing in a yaml file is important. Each entry is a new line, and one space after the colon.
Next, edit js-discourse.js and view the configuration at the top. Remember that java-script is run client side, so setting the update time low will hammer your server from many locations.
To recap:
- Add Access-Control headers to your nginx/apache config.
- Install httparty and json. Edit your Gemfile if you use one, otherwise install directly.
- Add the liquid tag to whatever layout you want comments for.
- Add needed information to your configuration yaml file.
- Add needed information to
js-discourse.js
- Generate your site!
Congrats! You made it. You should be able to generate your site and all of your posts will sync. It’s important to note that the folder you created stores a pstore file with the title of your post. If it can’t find these for some reason, when you generate you will create new posts with duplicated content. While it won’t delete the old posts, you’ll find that it will load comments from your newly duplicated post instead of the old one. Treat these files just like your database, carefully!
It looks something like this. I didn’t style the output yet, though.
Stuff I want to fix!
1. I take the posts full contents over to discourse with no attempts to check the limits. If you don't write a lot you might like this, otherwise maybe we will both find what happens when you use the API to make a really long post! You might have to edit them down by hand for now.
2. Formatting assumes markdown.
3. It actually runs twice per post, for reasons I can't figure out.
Extra Notes
I've detailed some of the implementation in the posts above, but if you use some other kind of site generator all you need to create is a div/span with an ID of comments, and an attritube called "tid." Then, you can just load the javascript and comments will render in that space. The topic ID is the number that follows after `/t//` and is not the last number.
And if you’re really looking to build it out in some other kind of framework I’d recommend looking at the original wp-discourse. Or, just load up /t/<topicID>/wordpress.json?best=number and parse it from there.
Not Reccomended: PHP proxy instead of CORS Header
I don’t reccomend this approach at first, because it can create some security issues if your script is not secured. This likely won’t happen… but you never really know. This is the php script.
Edit line 19 of js-discourse.js from:
BASE_URL + '/t/' + $('.comments').attr('tid') + '/wordpress.json?best=' + COMMENTS
to:
'http://<your-blog-url>/ba-simple.proxy.php?url=http%3A%2F%2F' + BASE_URL + '%2Ft%2F' + $('.comments').attr('tid') +'%2Fwordpress.json%3Fbest%3D' + COMMENTS
Then, replace every instance of a.posts with a.contents.posts.