fb_canvas.module in Drupal for Facebook 7.3
Same filename and directory in other branches
This module provides support for Canvas page applications. Use Drupal to power traditional Facebook Apps.
See also fb_connect.module for Facebook Connect.
File
fb_canvas.moduleView source
<?php
/**
* @file
*
* This module provides support for Canvas page applications. Use
* Drupal to power traditional Facebook Apps.
*
* See also fb_connect.module for Facebook Connect.
*
*/
// Option to require_login() on all canvas pages.
define('FB_CANVAS_OPTION_ALLOW_ANON', 1);
define('FB_CANVAS_OPTION_REQUIRE_LOGIN', 2);
define('FB_CANVAS_VAR_PROCESS_FBML', 'fb_canvas_process_fbml');
define('FB_CANVAS_VAR_PROCESS_FBML_FORM', 'fb_canvas_process_fbml_form');
define('FB_CANVAS_VAR_PROCESS_IFRAME', 'fb_canvas_process_iframe');
define('FB_CANVAS_VAR_PROCESS_ABSOLUTE', 'fb_canvas_process_absolute_links');
/**
* Implements hook_menu().
*/
function fb_canvas_menu() {
$items = array();
// Admin pages
$items[FB_PATH_ADMIN . '/fb_canvas'] = array(
'title' => 'Canvas Pages',
'description' => 'Configure Canvas Pages',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'fb_canvas_admin_settings',
),
'access arguments' => array(
FB_PERM_ADMINISTER,
),
'file' => 'fb_canvas.admin.inc',
'type' => MENU_LOCAL_TASK,
);
return $items;
}
/**
* Implements hook_fb().
*/
function fb_canvas_fb($op, $data, &$return) {
$original_uid =& drupal_static(__FUNCTION__);
global $user;
$fb = isset($data['fb']) ? $data['fb'] : NULL;
$fb_app = isset($data['fb_app']) ? $data['fb_app'] : NULL;
if ($op == FB_OP_CURRENT_APP) {
if (function_exists('fb_settings')) {
if (fb_settings(FB_SETTINGS_TYPE) == FB_SETTINGS_TYPE_CANVAS) {
// fb_settings.inc has determined this is a canvas page.
if ($id = fb_settings(FB_SETTINGS_CB)) {
// Using fb_url_rewrite.
$fb_app = fb_get_app(array(
'id' => $id,
));
if (!$fb_app) {
// DEPRECATED. For backward compatibility, accept apikey in FB_SETTINGS_CB
$fb_app = fb_get_app(array(
'apikey' => $app_key,
));
}
if (!$fb_app) {
// DEPRECATED. For backward compatibility, accept label in FB_SETTINGS_CB
$fb_app = fb_get_app(array(
'label' => $app_key,
));
}
}
elseif ($id = fb_settings(FB_SETTINGS_ID)) {
// New SDK includes ID when session is present.
$fb_app = fb_get_app(array(
'id' => $id,
));
}
elseif ($apikey = fb_settings(FB_SETTINGS_APIKEY)) {
// Old SDK tells us APIKEY. Deprecated.
$fb_app = fb_get_app(array(
'apikey' => $apikey,
));
}
}
}
if ($fb_app) {
$return = $fb_app;
}
}
elseif ($op == FB_OP_INITIALIZE) {
// Get our configuration settings.
$fb_canvas_data = _fb_canvas_get_config($fb_app);
$is_canvas = FALSE;
$use_ob = FALSE;
if (fb_canvas_is_iframe()) {
// Use buffer to process iframe markup.
$is_canvas = TRUE;
$use_ob = variable_get(FB_CANVAS_VAR_PROCESS_IFRAME, TRUE);
}
// Store entire page in output buffer. Will post-process on exit.
if ($use_ob) {
ob_start();
$GLOBALS['fb_canvas_post_process'] = TRUE;
}
if ($is_canvas && current_path() == variable_get('site_frontpage', 'node')) {
if ($fb
->getUser()) {
$front = $fb_canvas_data['front_added'];
}
else {
$front = $fb_canvas_data['front_anonymous'];
}
if ($front) {
menu_set_active_item(drupal_get_normal_path($front));
}
}
}
elseif ($op == FB_OP_POST_INIT) {
if (fb_canvas_is_iframe()) {
// The ?destination=... url param means something to drupal but something
// else to facebook. If ?fb_canvas_destination=... is set, we honor that.
if (isset($_REQUEST['fb_canvas_destination'])) {
$_REQUEST['destination'] = $_REQUEST['fb_canvas_destination'];
}
// Include our javascript.
drupal_add_js(array(
'fb_canvas' => array(
'fbu' => fb_facebook_user(),
'uid' => $GLOBALS['user']->uid,
'canvas' => $fb_app->canvas,
),
), 'setting');
drupal_add_js(drupal_get_path('module', 'fb_canvas') . '/fb_canvas.js');
}
// Include our admin hooks.
if (fb_is_fb_admin_page()) {
require drupal_get_path('module', 'fb_canvas') . '/fb_canvas.admin.inc';
}
}
elseif ($op == FB_OP_EXIT) {
/* We do some unpleasant stuff in this hook... on FBML canvas
pages we might use $fb->redirect(), in which case other
modules' hook_exit() might not be called.
In other cases we call drupal_goto(), in which case other
modules' hook_exit() might be called twice. I hate to do this
but so far have not figured another way. And so far no
problems... if problems arise, please post to issue queue.
*/
$destination = $return;
if (isset($GLOBALS['fb_canvas_post_process']) && $GLOBALS['fb_canvas_post_process']) {
$output = ob_get_contents();
ob_end_clean();
if (fb_canvas_is_iframe()) {
include_once drupal_get_path('module', 'fb') . '/fb.process.inc';
$output = fb_process($output, array(
'add_target' => '_top',
'absolute_links' => variable_get(FB_CANVAS_VAR_PROCESS_ABSOLUTE, TRUE),
'to_canvas' => $fb_app->canvas,
));
}
}
if (fb_canvas_is_iframe() && !isset($GLOBALS['_fb_canvas_goto'])) {
if ($destination) {
// Fully qualified URLs need to be modified to point to facebook app.
// URLs are fully qualified when a form submit handler returns a path,
// or any call to drupal_goto.
$app_destination = fb_canvas_fix_url($destination, $fb_app);
// If here, drupal_goto has been called, but it may not work within a
// canvas page, so we'll use Facebook's method.
// Unfortunately, other modules' hook_exit() may not be called.
if (fb_verbose()) {
watchdog('fb_debug', "FB_OP_EXIT on canvas page redirecting to {$app_destination} (original destination was {$destination}).");
}
fb_iframe_redirect($app_destination);
}
}
if (isset($output)) {
print $output;
}
}
}
/**
* Is the current request being displayed in an iframe canvas page?
*/
function fb_canvas_is_iframe() {
// Use either parameters passed from facebook, or url rewriting.
return fb_settings(FB_SETTINGS_TYPE) == FB_SETTINGS_TYPE_CANVAS;
}
/**
* Helper returns configuration for this module, on a per-app basis.
*/
function _fb_canvas_get_config($fb_app) {
$fb_app_data = fb_get_app_data($fb_app);
$fb_canvas_data = isset($fb_app_data['fb_canvas']) ? $fb_app_data['fb_canvas'] : array();
// Merge in defaults
$fb_canvas_data += array(
'require_login' => FB_CANVAS_OPTION_ALLOW_ANON,
// @TODO - can this still be supported?
'front_anonymous' => NULL,
'front_loggedin' => NULL,
// Facebook API no longer supports this.
'front_added' => NULL,
);
return $fb_canvas_data;
}
/**
* Implements hook_form_alter.
*/
function fb_canvas_form_alter(&$form, &$form_state, $form_id) {
if (isset($form['fb_app_data']) && is_array($form['fb_app_data'])) {
// Add our settings to the fb_app edit form.
//require 'fb_canvas.admin.inc';
fb_canvas_admin_form_alter($form, $form_state, $form_id);
}
if (!empty($_REQUEST['signed_request']) && empty($form['signed_request']) && fb_is_canvas()) {
// Facebook will pass our canvas pages the important signed_request.
// When we submit a form, that data will be lost unless we explicitly include it in the form.
$form['signed_request'] = array(
'#type' => 'hidden',
'#value' => $_REQUEST['signed_request'],
);
}
}
/**
* Uses javascript on iframe canvas pages change top frame, otherwise drupal_goto().
*
* @see drupal_goto()
*/
function fb_canvas_goto($path) {
global $_fb, $_fb_app;
if ($_fb && fb_canvas_is_iframe()) {
$url = fb_canvas_fix_url(url($path, array(
'absolute' => TRUE,
)), $_fb_app);
// Allow modules to react to the end of the page request before redirecting.
// We do not want this while running update.php.
if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
$GLOBALS['_fb_canvas_goto'] = TRUE;
// prevents fb_canvas_exit from calling redirect.
module_invoke_all('exit', $url);
}
fb_iframe_redirect($url);
}
else {
drupal_goto($path);
}
exit;
}
/**
* Define custom_url_rewrite_outbound() if not defined already.
*
* The bulk of URL rewriting is performed in fb_url_rewrite.inc. That file
* should be included in settings.php. The url rewriting below was originally
* an attempt to define those function here, only for canvas pages. That
* turned out to not be possible, so now the function just changes the
* destination parameter to not confict with facebook's parameter of the same
* name.
*
* For best results, admins should include fb_url_rewrite in their settings.php.
*
* @see fb_url_rewrite.inc
*/
/* not needed D7
if (!function_exists('custom_url_rewrite_outbound')) {
function custom_url_rewrite_outbound(&$path, &$options, $original_path) {
fb_canvas_url_outbound_alter($path, $options, $original_path);
}
}
*/
/**
* Implements hook_url_outbound_alter().
*
* @param $options
* If $options['fb_canvas'] == TRUE, create an absolute URL to a canvas
* page. The URL will begin http://apps.facebook.com/... Also if
* $options['fb_canvas'] is an application label the url will link to that
* particular application.
*/
function fb_canvas_url_outbound_alter(&$path, &$options, $original_path) {
// use $options['fb_url_alter'] = FALSE to suppress any alteration.
if (isset($options['external']) && $options['external'] || isset($options['fb_url_alter']) && $options['fb_url_alter'] === FALSE) {
return;
}
if (isset($options['fb_canvas']) && is_string($options['fb_canvas'])) {
$fb_app = fb_get_app(array(
'label' => $options['fb_canvas'],
));
}
else {
$fb_app = isset($GLOBALS['_fb_app']) ? $GLOBALS['_fb_app'] : NULL;
}
if ($fb_app && isset($fb_app->canvas)) {
if (isset($options['fb_canvas']) && $options['fb_canvas']) {
// Make a url starting with apps.facebook.com/...
$options[FB_SETTINGS_CB] = FALSE;
// prevent fb_url_rewrite.inc from inserting 'fb_cb'.
$options['absolute'] = TRUE;
$options['base_url'] = fb_protocol() . "://apps.facebook.com/{$fb_app->canvas}";
}
if (fb_canvas_is_iframe()) {
if (empty($options['absolute'])) {
// Could append session param to internal links. But for now we rely on fb_process().
}
else {
//dpm($options, "fb_canvas_url_outbound_alter($path)");
}
// Drupal has a habit of adding ?destination=... to some URLs.
// And Facebook for no good reason screws up when you do that.
if (!empty($options['query'])) {
$options['query'] = str_replace('destination=', 'fb_canvas_destination=', $options['query']);
}
}
}
}
/*
* Implements hook_custom_theme().
*
* For canvas pages we use app-specific theme. For this function to succeed,
* fb_canvas.module must come after fb.module in the module weights (it is by
* default).
*/
function fb_canvas_custom_theme() {
if (fb_canvas_is_iframe()) {
// Get our configuration settings.
$fb_canvas_data = _fb_canvas_get_config($GLOBALS['_fb_app']);
if ($custom_theme = $fb_canvas_data['theme_iframe']) {
return $custom_theme;
}
}
}
/**
* Implements hook_preprocess_html().
*
* Add canvas page specific body classes.
*/
function fb_canvas_preprocess_html(&$variables) {
if (fb_is_canvas()) {
$variables['classes_array'][] = 'fb_canvas-resizable';
$variables['classes_array'][] = 'fb-canvas';
}
}
Functions
Name | Description |
---|---|
fb_canvas_custom_theme | |
fb_canvas_fb | Implements hook_fb(). |
fb_canvas_form_alter | Implements hook_form_alter. |
fb_canvas_goto | Uses javascript on iframe canvas pages change top frame, otherwise drupal_goto(). |
fb_canvas_is_iframe | Is the current request being displayed in an iframe canvas page? |
fb_canvas_menu | Implements hook_menu(). |
fb_canvas_preprocess_html | Implements hook_preprocess_html(). |
fb_canvas_url_outbound_alter | Implements hook_url_outbound_alter(). |
_fb_canvas_get_config | Helper returns configuration for this module, on a per-app basis. |