Instagram Liquid Tag Plugin for Jekyll and Octopress
November 27, 2011Being new to the world of Ruby (and obviously Jekyll), I thought a good initial learning experience would be to write a liquid tag for Jekyll to display an Instagram photo. I finished up a decent enough version of the code, and it’s actually in use over at lukelov.es to display all my Instagrams. Check out this page for a complete example of what the finished product looks like.
It is a simple liquid tag which takes one parameter, the ID of a media item from Instagram. The code then fetches the media item using Instagram’s ruby gem, and writes a bunch of relevant HTML to the page.
I currently have it displaying:
- the 612x612 version of the image (which links to the photo on Instagram)
- the filter used to create the image
- a static map of where the image was taken using the Google Static Map API
- the name of the location where the image was taken
- a link to comment on the Instagram using webstagram
Obviously, the location information is only displayed if the Instagram has that data associated with it.
The embedded gist below should be the same as the code being used in the lukelov.es repository.
If you have questions, comments, bugs, etc, please leave a comment on this post or the gist, and if you’d like to contribute fixes or features directly, you can submit a pull request for this file.
# A Liquid tag for Jekyll sites that allows embedding Instagrams | |
# by: Luke Karrys | |
# | |
# Example usage: {% instagram media_id %} | |
require 'instagram' | |
require 'json' | |
module Jekyll | |
class InstagramTag < Liquid::Tag | |
def initialize(tag_name, markup, token) | |
super | |
access_token_file = File.expand_path "../.instagram_access_token", File.dirname(__FILE__) | |
@access_token = File.open(access_token_file).gets | |
@image_res = "standard_resolution" | |
@markup = markup | |
@cache_folder = File.expand_path "../.instagram-cache", File.dirname(__FILE__) | |
FileUtils.mkdir_p @cache_folder | |
end | |
def render(context) | |
id = @markup.strip | |
media = get_cached_media(id) || get_media(id) | |
gen_html_output JSON.parse(media) | |
end | |
def gen_html_output(media) | |
loc_name, lat, lon = nil, nil, nil | |
id = media["id"] | |
link = media["link"] | |
src = media["images"][@image_res]["url"] | |
image_w = media["images"][@image_res]["width"] | |
image_h = media["images"][@image_res]["height"] | |
location = media["location"] | |
filter = media["filter"] | |
caption = media["caption"] | |
created = Time.at(Integer(media["created_time"])).strftime("%I:%M%p %B %e, %Y") | |
title = caption ? caption["text"] : "Untitled Instagram" | |
output = "<p><a href='#{link}'><img src='#{src}' alt='#{title}' /></a>" | |
output += "<br/>Filtered with #{filter} through <a href='http://instagram.com'>Instagram</a></p><!--more-->" | |
if location | |
loc_name = location["name"] | |
lat = location["latitude"] | |
lon = location["longitude"] | |
coords = "#{lat},#{lon}" | |
loc_alt = loc_name || coords | |
output += "<p><a href='http://maps.google.com?q=#{coords}'>" | |
output += "<img border='0' " | |
output += "src='http://maps.googleapis.com/maps/api/staticmap?center=#{coords}&markers=#{coords}&zoom=14&size=#{image_w}x200&sensor=false' " | |
output += "alt='#{loc_alt}' /></a>" | |
if loc_name | |
output += "<br/>Taken at #{loc_name}" | |
end | |
output += "</p>" | |
end | |
output += "<p><a href='http://web.stagram.com/p/#{id}#photo#{id}'>Leave a comment</a></p>" | |
end | |
def get_cache_file_for(id) | |
File.join @cache_folder, "#{id}.cache" | |
end | |
def cache(id, data) | |
cache_file = get_cache_file_for id | |
File.open(cache_file, "w") do |io| | |
io.write data | |
end | |
end | |
def get_media(id) | |
client = Instagram.client(:access_token => @access_token) | |
data = client.media_item(id).to_json | |
cache id, data unless @cache_disabled | |
data | |
end | |
def get_cached_media(id) | |
cache_file = get_cache_file_for id | |
File.read cache_file if File.exist? cache_file | |
end | |
end | |
end | |
Liquid::Template.register_tag("instagram", Jekyll::InstagramTag) |
On a side note, I also came up with a solution for how to batch create Instagram posts (as you might’ve noticed by the hundreds of Instagram posts on lukelov.es). The solution was to create a few Rake tasks similar to the ones that are already being used by Octopress to create new posts and pages. I will be writing another blog post soon detailing those and how they work, but if you would like a sneak peak, checkout the Rakefile for lukelov.es.