In this tutorial, we are going to create our own version of Facebook’s wall. We will be using Facebook’s Graph API with jQuery, and the template plugin. The jQuery.tmpl plugin will allow us to define templates within our page, and convert the posts we’ve obtained from the API into a real HTML page.
You can use today’s example to display a feed of the latest posts on your FB page or profile on your website.
Before we begin, lets say a few words about the Facebook API.
Update on June 19th, 2011: Recently Facebook introduced some changes to their API that broke this script. They now require that you use an access token in order to fetch the page feed, used by this example. The last section of this tutorial explains how to obtain such an access token.
The Graph API
The Graph is Facebook’s solution to providing an interface to every object that exists in the site, along with its connections to other objects. Every page that you see on the site has a corresponding graph representation, be it a user, photo, group, status update or anything else. The API also supports JSONP requests, which makes it really easy to use with jQuery.
Note: although the API gives you access to everything on Facebook, you will need an API key to read non-public content. As this tutorial does not use an API key, it will only work if your wall is publicly accessible.
We will be using two API datapoints – one for selecting the latest posts, and the other for selecting the full name and avatar of the page. You can see sample responses below:
03 |
"id" : "45576747489_10150136051797490" , |
05 |
"name" : "Smashing Magazine" , |
06 |
"category" : "Website" , |
09 |
"message" : "Creating a sphere with 3D CSS" , |
12 |
"name" : "Creating a sphere with 3D CSS \u2013 Paul Hayes" , |
13 |
"caption" : "www.paulrhayes.com" , |
14 |
"description" : "A professional slice of newly.." , |
25 |
"created_time" : 1301325483, |
26 |
"updated_time" : 1301325483, |
30 |
"id" : "100000643422735" |
The JSON response above contains information on every one of the posts published by Smashing Magazine. Some of the fields contain data about the creation/modification date, number of likes and comments, title and description, and a type. This request could return status updates, shared links, uploaded photos andvideos, and more.
We also need to make an additional request so we can obtain the avatar, associated with the page (it is not contained in the post responses):
03 |
"name" : "Smashing Magazine" , |
06 |
"category" : "Website" , |
09 |
"username" : "smashmag" , |
10 |
"company_overview" : "Founded in September 2006.." , |
11 |
"mission" : "The offical Smashing Magazine pa..!" , |
12 |
"products" : "Looking for a web design job? Che.." |
The picture field above gives us what we need. It is a bit of a waste to request so much data, so in the plugin we are actually limiting the returned fields to only what we need.
The Templates
Now lets say a few words about the jQuery templates. As the Graph API returns valid JSON data, it is a great candidate to experiment with jQuery’s template plugin. This official plugin enables us to define HTML building blocks with an easy to use markup. This saves us from having to manually create HTML elements, concatenate strings and escape character sequences.
The templates themselves may be inserted inline in a special script tag, or can be received via an AJAX call from a separate file. In this tutorial, I’ve chosen the first approach as it is simple and straightforward.
Each template has the following form:
1 |
< script id = "someID" type = "text/x-jquery-tmpl" > |
2 |
<!-- HTML markup coupled with template tags --> |
This is a script tag which, because of the type attribute, is not recognized by the browser, so it is not evaluated nor shown. What is more, its content is treated as character data and is not parsed, which is perfect for the task of holding our templates. We can then use jQuery’s tmpl() method and render it into actual HTML markup (more on that in a moment).
Here is the first template, which creates the heading of the page:
1 |
< script id = "headingTpl" type = "text/x-jquery-tmpl" > |
2 |
< h1 >${name}< span >on Facebook</ span ></ h1 > |
The ${} template tag gets replaced with the value of the name property of the object, that is passed to the tmpl() method, which in our case is the name of the facebook page.
For a complete list of template tags and methods, read through the jQuery Template documentation.
The other template, which displays the individual posts is a bit more complex and employs some of the more advanced templating features:
01 |
< script id = "feedTpl" type = "text/x-jquery-tmpl" > |
03 |
< img src = "${from.picture}" /> |
07 |
< p >{{html message}}</ p > |
08 |
{{if type == "link" }} |
11 |
< img src = "${picture}" /> |
14 |
< p >< a href = "${link}" target = "_blank" >${name}</ a ></ p > |
24 |
${comments.count} Comment{{if comments.count>1}}s{{/if}} |
29 |
${likes.count} Like{{if likes.count>1}}s{{/if}} |
Inside the template tags we can have any JavaScript expressions, even method and function calls. This is especially helpful when building the {{if}}
statements, as you can see from the code above, where we check the number of likes and comments.
One feature of the ${}
tag is that it escapes the textual value before inserting it into the template. However in some cases this is not what you need. For example the message variable holds HTML code that we want to display as is. This is why we use the {{html}}
tag instead, which preserves the original format of the code.
And here is the HTML document we end up with:
04 |
< meta http-equiv = "Content-Type" content = "text/html; charset=utf-8" /> |
05 |
< title >Making a Custom Facebook Wall with jQuery | Tutorialzine Demo</ title > |
06 |
< link rel = "stylesheet" type = "text/css" href = "css/styles.css" /> |
17 |
<!-- jQuery templates. Not rendered by the browser. Notice the type attributes --> |
19 |
< script id = "headingTpl" type = "text/x-jquery-tmpl" > |
20 |
< h1 >${name}< span >on Facebook</ span ></ h1 > |
23 |
< script id = "feedTpl" type = "text/x-jquery-tmpl" > |
25 |
< img src = "${from.picture}" class = "avatar" /> |
29 |
< p class = "message" >{{html message}}</ p > |
30 |
{{if type == "link" }} |
31 |
< div class = "attachment" > |
33 |
< img class = "picture" src = "${picture}" /> |
35 |
< div class = "attachment-data" > |
36 |
< p class = "name" >< a href = "${link}" target = "_blank" >${name}</ a ></ p > |
37 |
< p class = "caption" >${caption}</ p > |
38 |
< p class = "description" >${description}</ p > |
44 |
< p class = "meta" >${created_time} · |
46 |
${comments.count} Comment{{if comments.count>1}}s{{/if}} |
51 |
${likes.count} Like{{if likes.count>1}}s{{/if}} |
61 |
< script src = "js/jquery.tmpl.min.js" ></ script > |
62 |
< script src = "js/script.js" ></ script > |
The #wall div is going to be dynamically populated with the Graph API data, after it has been rendered using our templates. You can see the templates themselves at the bottom of the file. Before the closing body tag, I have included the jQuery library, the jQuery.tmpl plugin, and our script.js file, which we will be discussing next.
jQuery Code
As we have all the pieces in place, we can finally get down to writing our facebook wall plugin.
script.js
001 |
// Creating our plugin. |
005 |
$.fn.facebookWall = function (options){ |
007 |
options = options || {}; |
010 |
throw new Error( 'You need to provide an user/page id!' ); |
013 |
// Default options of the plugin: |
016 |
limit: 15 // You can also pass a custom limit as a parameter. |
019 |
// Putting together the Facebook Graph API URLs: |
026 |
$.when($.getJSON(graphUSER),$.getJSON(graphPOSTS)).done( function (user,posts){ |
028 |
// user[0] contains information about the user (name and picture); |
029 |
// posts[0].data is an array with wall posts; |
036 |
$.each(posts[0].data, function (){ |
038 |
// We only show links and statuses from the posts feed: |
039 |
if ( this .type != 'link' && this .type!= 'status' ){ |
043 |
// Copying the user avatar to each post, so it is |
044 |
// easier to generate the templates: |
045 |
this .from.picture = fb.user.picture; |
047 |
// Converting the created_time (a UNIX timestamp) to |
048 |
// a relative time offset (e.g. 5 minutes ago): |
049 |
this .created_time = relativeTime( this .created_time*1000); |
051 |
// Converting URL strings to actual hyperlinks: |
052 |
this .message = urlHyperlinks( this .message); |
057 |
// Rendering the templates: |
058 |
$( '#headingTpl' ).tmpl(fb.user).appendTo(wall); |
060 |
// Creating an unordered list for the posts: |
061 |
var ul = $( '<ul>' ).appendTo(wall); |
063 |
// Generating the feed template and appending: |
064 |
$( '#feedTpl' ).tmpl(fb.posts).appendTo(ul); |
073 |
function urlHyperlinks(str){ |
074 |
return str.replace(/\b((http|https):\/\/\S+)/g, '<a href="$1" target="_blank">$1</a>' ); |
077 |
function relativeTime(time){ |
081 |
var period = new Date(time); |
082 |
var delta = new Date() - period; |
084 |
if (delta <= 10000) { // Less than 10 seconds ago |
091 |
millisecond: 1, // ms -> ms |
092 |
second: 1000, // ms -> sec |
093 |
minute: 60, // sec -> min |
094 |
hour: 60, // min -> hour |
095 |
day: 24, // hour -> day |
096 |
month: 30, // day -> month (roughly) |
097 |
year: 12 // month -> year |
100 |
for ( var key in conversions) { |
101 |
if (delta < conversions[key]) { |
106 |
delta = delta / conversions[key]; |
110 |
// Pluralize if necessary: |
112 |
delta = Math.floor(delta); |
113 |
if (delta !== 1) { units += 's' ; } |
114 |
return [delta, units, "ago" ].join( ' ' ); |
We are using the $.getJSON
functions to request information from the Graph API. But you may notice that we are not using it as we have in previous tutorials, namely by providing a callback function as its second parameter. This is because we want both calls to the Graph API to be run in the same time (speed all the way), which is not possible with a simple callback.
As of jQuery 1.5, all AJAX methods return a deferred object, which basically allows us to group a number of AJAX calls in a $.when(). After both of the AJAX requests complete successfully, the done method is executed once.
After this, we can simply render the templates:
1 |
// Rendering the templates: |
2 |
$( '#headingTpl' ).tmpl(fb.user).appendTo(wall); |
4 |
// Creating an unordered list for the posts: |
5 |
var ul = $( '<ul>' ).appendTo(wall); |
7 |
// Generating the feed template and appending: |
8 |
$( '#feedTpl' ).tmpl(fb.posts).appendTo(ul); |
The tmpl() method takes a JavaScript object or array, and renders the template once per each element. The templates are specified by their ids (the #headingTpl and #feedTpl script elements in our case).
Finally we only have to call the plugin in document.ready with the ID of your page, and your access token (more on this in a moment):
1 |
$(document).ready( function (){ |
3 |
// Calling our plugin with a page id: |
4 |
$( '#wall' ).facebookWall({ |
6 |
access_token: '19304297594165|ZGyz1d0clt2XO3AyrjHmrKORo' |