Drupal for Facebook, Quick posting to FB Streams

In a recent project update to our RV Parks site we wanted to add some Facebook integration points. Add a few 'Like' buttons for Facebook on pages as well as the ability to login using Facebook connect. Numerous modules can do this for Drupal, but we moved forward with Drupa for Facebook (demo site at http://www.drupalforfacebook.org) based on some other features I want to talk about here.

Drupal for Facebook also has Facebook Stream integration in a submodule, which we wanted to use to post reviews written by our users to their FB walls, or streams as they are now called. The Streams module is more of an API that you need to implement in a custom module, but a fine example is given as a recipe in the Drupal for Facebook documentation at http://drupal.org/node/685320. A great example that worked for us with a bit of our own tweaks.

But, what we really want to do is post directly to FB without the extra popup confirmation that is used the example. We wanted to speed up the workflow. To do this we need get an 'Extended Permission' from Facebook for each user. The Extended Permission contrib module that is packaged with Drupal for Facebook exposes these permission, but only on the user's profile page, which wasn't ideal for our use case.

So we need to obtain the extended permission skip the confirmation, and then we need to update the code to bypass the confirmation screen if we do have the permission. To do this we have to update the form_alter hook in the example to ask for the permission, and then update the nodeapi call to skip the confirmation if the permission is given.

Here is the updated form_alter code from the example:

function dff_custom_form_alter(&$form, $form_state, $form_id) {

   if (isset($GLOBALS['_fb']) && fb_facebook_user()) {

   $fb = $GLOBALS['_fb'];
   $fb_app = $GLOBALS['_fb_app'];

   if ($form['#id'] == 'node-form') {
     // Add checkbox to control feed publish.
     $form['dff_custom']['stream_publish'] = array(
       '#type' => 'checkbox',
       '#title' => 'Share on Facebook',
       '#default_value' => TRUE,
     );
   }
   else if ($form['form_id']['#value'] == 'comment_form') {
     // Add checkbox to control feed publish.
     $form['dff_custom']['stream_publish'] = array(
       '#type' => 'checkbox',
       '#title' => 'Share on Facebook',
       '#default_value' => TRUE,
     );
   }

   try {
       $has_perm = fb_call_method($fb, 'users.hasAppPermission', array(
       'ext_perm' => 'publish_stream',
         'uid' => $fbu,
       ));
     } catch (Exception $e) {
     fb_log_exception($e, t('Call to users.hasAppPermission(%key) failed.', array('%key' => $key)));
   }

     //If the permission has not be granted yet, add a link to a new window that asks for the permission.
     if (!$has_perm) {
     $form['dff_custom']['stream_publish']['#description'] =
       l('Auto share all reviews (skip confirmation popup)',
'http://www.facebook.com/authorize.php',
       array('query' => 'api_key='.$fb_app->apikey.'&v=1.0&ext_perm=publish_stream&next=http://www.rvparking.com/user/'.$user->uid.'&next_cancel=http://www.rvparking.com/user/'.$user->uid, 'html' => TRUE, 'attributes' => array('target' => '_blank'))
       );
     }

   }

}

Specifically the try/catch code (couched from the Extended Permissions module) is checking to see if the 'publish_stream' extended permission has already been granted by this user. If not, then a link is added to the description of the 'Share on Facebook' form element.

Next we update the hook_nodeapi function (similar edits needed for comments, not shown here).

/**
* Implementation of hook_nodeapi().
*
* Publish to facebook Walls when users submit nodes.
*/
function dff_custom_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
   if ($op == 'insert' || $op == 'update') {
     if (isset($node->stream_publish) && $node->stream_publish) {
       //dpm($node, "dff_custom_nodeapi, publishing to stream");
       // http://wiki.developers.facebook.com/index.php/Attachment_(Streams)
       $attachment = array(
         'name' => $node->title,
         'href' => url('node/' . $node->nid, array('absolute' => TRUE)),
         'description' => $node->teaser,
       );

       $user_message = t('Check out my latest post on !site...',
       array('!site' => variable_get('site_name', t('my Drupal for Facebook powered site'))));
       $actions = array();
       $actions[] = array('text' => t('Read More'),
         'href' => url('node/'.$node->nid, array('absolute' => TRUE)),
       );

       $fb = $GLOBALS['_fb'];

       $fb_session = $fb->getSession();
       $fb->api_client->session_key = $fb_session['session_key'];
       $fb->api_client->expires = 0;

       try {
         $success_data = fb_call_method($fb, 'stream.publish', array(
           'session_key' => $fb_session['session_key'],
           'message' => $user_message,
           'attachment' => $attachment,
           'action_links' => json_encode($actions),
         ));
       } catch (Exception $e) {
         drupal_set_message("NOTTTT!!! Added on FB Wall: Showing Dialog.");
         fb_stream_publish_dialog(array('user_message' => $user_message,
           'attachment' => $attachment,
           'action_links' => $actions,
           ));
       }
     }
   }

}

Now we use the try/catch method to post the update to Facebook directly. The fb_call_method function is provided by Drupal for Facebook. If the user has granted the 'publish_stream' permission, then the post will succeed, if not then we use the normal fb_stream_publish_dialog method which will create a JS popup box after the form sumbits that will ask the user if they want post to Facebook.

Now we have much more streamlined posting to Facebook workflow. If no extended permission are granted, it behaved just like the example with a popup confirmation. But now in the form we ask for the extended permission, and if granted we speed up the posting to Facebook. Good for all.