Wednesday, June 8, 2011

Facebook Applications

facebookI’ve seen some how-to guides for getting started writing facebook apps on the web but none really cover everything fro
Publish Post
m start to finish. Even Facebook’s own documentation is somewhat disappointing. So to help others find their way around Facebook markup and the life cycle of a Facebook application here is a simple tutorial.It is a very basic app which aims to display a web image of the user’s choice a) in miniature on their profile, and b) in full on the application’s own canvas page. What is a canvas page? Simply the main page of your application that the user sees each time they click on your app.

Prereqs:
What you’ll need – an account on Facebook and a web hosting provider who will run php scripts and allows you to set up a database. I use mysql in this guide, but you can safely leave out the db steps if all you want to learn is the facebook-specific work flow stuff.

Step 1: Setting things up on Facebook.com
A Few things here -
1) Add the Facebook Developer Application to your profile if not done so already.
2) Set up new app, give it a name. Enter in the following details:
Canvas Callback URL – the full url of the canvas page to be stored on your server.
Canvas Url – the unique name for your app @http://apps.facebook.com/. You can flesh it out with icons, descriptions, etc too.
3) Once you get the hang of things it becomes obvious two app instances are needed for each separate application you create – one live and one test. However for the sake of brevity I’ll continue with a single instance.

Now it’s time to create your viral hit. Download the client libs of your choice and we’ll look at how to create a setup page for users that wish to add your app. For this demo I’ll be using the official PHP client.What we’ll be doing is showing a simple image. We’ll go through all use cases a user will walk through over the lifetime of a facebook app together with the main social networking elements that make the facebook platform such a powerful medium for app developers.

Step 2: Config on your side
Now for the config in your php script. Go to the file you entered in as the Canvas Callback URL – this is the jump-off point for all calls from Facebook to your application.

// Include the Facebook client library
require_once ('facebook.php');
// Set authentication variables
$appapikey = '<yourkeyhere>';
$appsecret = '<yoursecrethere>';
$facebook = new Facebook($appapikey, $appsecret);
// I also will be accessing my own database on almost every call so will set db up here
$username="<yourusername>";
$password="<yourpassword>";
$database="<yourdb>";
mysql_connect(localhost,$username,$password);
@mysql_select_db($database) or die( "Unable to select database");

You are now ready to interact with the Facebook api.

Step 3: Where to begin?
This was the first – and most dogged – question I asked myself when creating my first Facebook application. As it turns out the workflow is quite like any other web app, with a few bells and whistles tacked on.

Let’s imagine for a second that user A already has our completed app installed. User Bthen comes across it on User A’s profile, so they click through to the app’s canvas screen.

$url = '';
if(!($_GET['user']==NULL||$_GET['user']=='')){
//user wants to see someone elses profile
$user = $_GET['user'];
if(preg_match('/^[0-9]+z/', $user)){
//use id to retrieve img url from db
$query = 'select * from turl where userid = '.$user;
$result=mysql_query($query) or die("Couldn't execute query");
$url=mysql_result($result,0,"url");}?><img src="<?=$url?>" />

The above code looks for a ‘user’ variable in the http query. If it finds it (i.e. not null) it looks up the image url stored for the user sought (User A in this case) and displays.

I should also tell you a bit about the database at this stage. It is simply a single table (turl) holding two fields url and userid (as in facebook userid).

So we have one use case. But what if it’s user A who is clicking through to their own canvas page? Should we make any additions? Yes – we should give them the option of adding the image to their profile if they haven’t done already. Fortunately interactions like this that deal with Facebook UI and concepts such as profile can be easily taken care of declaratively through Facebook Markup Langauge (FBML). Here we add:

if($user==$facebook->api_client->users_getLoggedInUser()){
//user is looking at their own profile
?> <p class="section_button"><fb:add-section-button section="profile"></fb:add-section-button></p>}
else{
?>api_client->users_getLoggedInUser()?><a href="http://apps.facebook.com/<yourappname>">Add your web image</a>, if you haven't already!}

If the user is looking at their own web image but hasn’t yet displayed it on their profile (either in the boxes tab or on the left hand strip on their wall tab) they will see the add to profile image below:

Add to Profile

The else statement checks if it’s another users image page and if so a rudimentary viral feature appears – asking the viewer if they want to try the app out too.

Step 4: Allowing a new user to preview
OK so back to User B. Having clicked through to User A’s web image they like what they see – now they want to try things out for themselves. At this stage some FB devs like to force the user to install the app – with a call to $facebook->require_login() – before they can try it out for themselves. I don’t know about you but personally I find this a very annoying feature of 99% of FB apps so as a developer I want to give my users the option to preview their app first.

There is a drawback though.

$user = $facebook->require_login() is a really simple way of getting the user id, something you will need for virtually all meaningful interactions with the platform API. Otherwise there are all sorts of possible ways a user can land on your canvas page without their user id being specified in the various Facebook ID fields sent with each request. For example a user could enter the app url directly into the browser address bar or open from an email link.

Because the platform isn’t an exact science as such, with features, availability, etc changing quite a bit I’ve hacked around something that appears to work for me, i.e. it gets user ids in most situations without forcing an install on the user:

}else{
if(!(($_GET["fb_sig_canvas_user"]==NULL) ||($_GET["fb_sig_canvas_user"]==''))){
$user = $_GET["fb_sig_canvas_user"];}
elseif(!(($_REQUEST["fb_sig_user"]==NULL) ||($_REQUEST["fb_sig_user"]==''))){
$user = $_REQUEST["fb_sig_user"];}
else{
$user = $facebook->api_client->canvas_user;}
if(($user==NULL)||($user=='')){
//if not already, try redirect
if (!isset($_REQUEST['reload'])){
$facebook->redirect($app_base_url.'?reload');}
else{?><span>You must be logged into Facebook to access web image</span><?die();}}

Step 5: how to track your user base
Users.isAppUser has come under a lot of criticism. Well, from me at least. Because it only records if a user has previously authorised an app, and not if the app is currently authorised, facebook platform currently has no sure way of knowing if it is installed by a user right now. So we create our own solution with the previously mentioned db table turl. Turl’s two fields userid & url tell us if the user has authorised the app (userid is present) and what web image they have displayed (url). So now that we have the user id, we check for authorisation:

  else{
//set isAppUser
$query = 'select * from turl where userid = '.$user;$result = mysql_query($query) or die("Couldn't execute query");
if(mysql_num_rows($result)==1)
$isAppUser=true;
else
$isAppUser=false;
}

if authorised we get the image url and show it on the canvas:

if($isAppUser){
//display gfx, webform
$user = $facebook->require_login();
$query = 'select * from turl where userid = '.$user;
$result=mysql_query($query) or die("Couldn't execute query");
$url=mysql_result($result,0,"url");?><img src="<?=$url?>" /><p class="section_button"><fb:add-section-button section="profile"></fb:add-section-button></p> }

Step 6: Adding a user proper
We’re on our 6th step so lets take stock of where we are. We’ve taken into account a user viewing another users canvas page and also a user viewing their own page. We’ve also got the user’s id and, assuming a user’s been added to the database successfully, can tell if they have installed the app. Now we can begin to comtemplate how a user is added to our database.

First we should deal with the preview:

 else{
?><span>Want to display a web image of your choice on Facebook?  Enter the url here:</span><form action="." method="get"> <input name="url" type="text" /> <input value="Preview" type="submit" /></form><?}}
mysql_close();
?>

And so we have the above catchall statement added if the user is not currently using the app, inviting them to preview it. Once this form is submitted by the user we need to show the preview, so we include the following case before the form:

 elseif(!($_GET['url']==NULL||$_GET['url']=='')){
$url=$_GET['url'];?><img src="<?=$url?>" /><span>Happy with this?  Click to install app</span><form action="." method="get"> <input value="<?=$url?>" name="url" type="hidden" /><input name="add" type="hidden" /> <input value="Add Web Image" type="submit" /></form><?}

Now we also have the preview step. If the user wants to install at this stage we go ahead with the obligatory warning page and then we can perform the main installation tasks. So another case goes in above the previous one:

 elseif(isset($_GET['add'])){
$user=$facebook->require_login();
//once authorised FB forwards the user with all existing request variables - back to this page, so we can continue installation on our side
$url=$_GET[url];
$query = "insert into turl values ('$user','$url')";
mysql_query($query);
$fbml_profile = '<a href="http://apps.facebook.com/<yourappname>/?user='.$user.'"><img src="'.$url.'" width="182" height="182" /></a>';$fbml_boxes = '<a href="http://apps.facebook.com/<yourappname>/?user='.$user.'"><img src="'.$url.'" width="360" height="100" /></a>';
$facebook->api_client->profile_setFBML(null, $user, $fbml_boxes, null, null, $fbml_profile);

After the user authorises the application we add the user to our db and also set the fbml markup for displaying the chosen web image on their profile wall or boxes tab.

Step 7: Adding Viral Features
Along with maybe the application directory, this is the most powerful aspect of the Facebook platform for developers. Given the right incentives/marketing/branding/whatever you wish to call it, apps on facebook can spread like wildfire. We will implement two features commonly used by FB developers to reach the tipping point – app invites and newsfeed stories.

Both are normally done at app sign up time and are used to inform members of the users personal network. But they differ in that an invite is an explicit question targeted at friends of the user’s choice while adding it to a users newsfeed merely passively notifies people that they are using your application. It’s harder to get a user to send out invites because they aren’t always welcome but if a user does target them successfully it may lead to a higher sign up rate amongst their friends.

Step 7a: Application Invite
First the app invite. It takes the form of more FBML and presents itself in a separate page pretty much like the authorisation page, before redirecting the user back to our page again. You don’t want the user to send out any to friends who already have the application, so here’s the code to display only those who don’t yet have them:

  $fql = 'SELECT uid FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1='.$user.') AND has_added_app=1';$_friends = $facebook->api_client->fql_query($fql);
// Extract the user ID's returned in the FQL request into a new array.
$friends = array();
if (is_array($_friends) && count($_friends)) {
foreach ($_friends as $friend) {$friends[] = $friend['uid'];}}
// Convert the array of friends into a comma-delimeted string.
$friends = implode(',', $friends);
// Prepare the invitation text that all invited users will receive.
$content = <<<fbml><fb:name shownetwork="false" firstnameonly="true" uid="{$user}"> wants to see your web image!<fb:req-choice label="Add Your web image to your profile" url="{$facebook->get_add_url()}">FBML;?><fb:multi-friend-selector exclude_ids="<?php echo $friends;?>" rows="5" showborder="true" actiontext="Invite your friends not yet displaying their web image" max="20"></fb:multi-friend-selector></fb:req-choice></fb:name></fbml>

Step 7b: Wall Story
The Wall story request feature is implemented as a popup using FBJS – the subset of javascript allowed on Facebook canvas pages. It is slightly more complex than that unfortunately – you need to create a feed template first to describe the format of the story that will appear on users newsfeeds.

Go to the template editor tool to begin. We’ll create a simple feed that shows your application logo and invites people to try it or view their friends web image. First choose your application then create a one liner, note the special markup involved to allow personalisation. 3 main bits to note in this:

Short story template title & body:
Add in your message -> “{*actor*} added their web image”

Sample template data: very important for ensuring your story appears how you wish. Use it to experiment.

Action Link URL:To give friends a way of viewing the user’s own web image, enter the following -> “http://apps.facebook.com//?user={userid}”

Click through next, Register Template Bundle and note down the ID generated. It can get more powerful than this but it’s quite error prone for a beginner so lets keep things simple. We’re halfway there – now back to your php code:

 <script type="text/javascript">
var tpl_data={"status":"status","images":[{"src":"<yourapplogo>", "href":"http://apps.facebook.com/<yourapppage>"}],"userid":"<?=user?>"};
var user_msg = {"value":""};
var share_msg = "share with your friends";
Facebook.showFeedDialog(<feeddialogid>, tpl_data, "", "", null, share_msg, user_msg);</script><fb:request-form content="<?php echo htmlentities($content);?>" type="web image" invite="true" method="POST" action="http://apps.facebook.com/<youapppage>/"></fb:request-form>} </yourapplogo>

Enter your feed dialog ID in the code above, together with your app logo url, etc. As you can maybe workout, we substitute the the real data needed in tpl_data in place of the sample template data you seen in the feed templating tool. Note we pass in our own user variable, necessary to know which users image the friend wants to view.

Step 8: Deleting user records
Almost done. A user now can view other users web images & install one on their own profile. But what happens when a user deletes the app? To avoid our database potentially filling up with duplicate user accounts (and if we want to keep an accurate record of the total number of installed users), we must create a 2nd php script that Facebook can call when a user deletes our app.

To do this, create a 2nd script on your web host then go back into the FB dev application, click on the ‘more’ tab of our app then ‘edit settings’ -> ‘authentication’ -> ‘Post-Remove Callback URL’. Enter in the full URL of this script. All we need to do is delete the user from our db:

// Include the Facebook client library
require_once ('facebook.php');
// Set authentication variables
$appapikey = '<yourkeyhere>';
$appsecret = '<yoursecrethere>';
$facebook = new Facebook($appapikey, $appsecret);
$user = $facebook->get_loggedin_user();
if ($user != NULL && $facebook->fb_params['uninstall'] == 1) {
//The user has removed your app
$username="<yourusername>";
$password="<yourpassword>";
$database="<yourdb>";
mysql_connect(localhost,$username,$password);
@mysql_select_db($database) or die( "Unable to select database");
$query = 'delete from turl where userid = '.$user;mysql_query($query) or die("Couldn't execute query");}?>

And that’s that! A working Facebook application from the ground up with several important features explained.

For a complete listing of the code check out google docs add.php & remove.php

Need a more in-depth explanation?  In my opinion the book that offers the most clarity on the subject is Facebook Cookbook: Building Applications to Grow Your Facebook Empire

No comments:

Post a Comment