'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;
}
/**
* Implementation of hook_fb().
*/
function fb_canvas_fb($op, $data, &$return) {
static $original_uid;
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 (isset($_REQUEST[FB_APP_REQ_API_KEY]) &&
($apikey = $_REQUEST[FB_APP_REQ_API_KEY])) {
// If facebook has passed the app key, let's use that.
$fb_app = fb_get_app(array('apikey' => $apikey));
}
else {
if (function_exists('fb_settings')) {
// See fb_settings.inc
if ($id = fb_settings(FB_SETTINGS_APP_LABEL)) {
$fb_app = fb_get_app(array('id' => $id));
}
}
}
if ($fb_app)
$return = $fb_app;
}
elseif ($op == FB_OP_INITIALIZE) {
// Get our configuration settings.
$fb_app_data = fb_get_app_data($fb_app);
$fb_canvas_data = $fb_app_data['fb_canvas'];
$is_canvas = FALSE;
// Set an app-specific theme.
global $custom_theme; // Set by this function.
if (fb_canvas_is_fbml()) {
$custom_theme = $fb_canvas_data['theme_fbml'];
$is_canvas = TRUE;
$use_ob = variable_get(FB_CANVAS_VAR_OB_FBML, TRUE);
}
elseif (fb_canvas_is_iframe()) {
$custom_theme = $fb_canvas_data['theme_iframe'];
$is_canvas = TRUE;
$use_ob = variable_get(FB_CANVAS_VAR_OB_IFRAME, TRUE);
}
if ($is_canvas) {
// We are serving a canvas page.
if ($fb_canvas_data['require_login'] == FB_CANVAS_OPTION_REQUIRE_LOGIN) {
// The application is configured to require login on all canvas pages.
// However, there are exceptions.
if (fb_is_profile_tab()) {
// Redirects are not allowed for the profile tab.
}
else {
// There may be other exceptions, for example some ajax callbacks. Potential todo item.
$fb->require_login();
}
}
// Remember the user id. If fb_user.module changes it, we'll need to refresh the page. See FB_OP_POST_INIT.
$original_uid = $user->uid;
// Hack to init the theme before _drupal_maintenance_theme initializes the wrong one.
if (variable_get('site_offline', FALSE)) {
$dummy = theme('dummy');
}
}
// Use buffer for form posts.
if (!$use_ob && fb_canvas_handling_form()) {
$use_ob = variable_get(FB_CANVAS_VAR_PROCESS_FBML_FORM, 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 &&
$_GET['q'] == drupal_get_normal_path(
variable_get('site_frontpage', 'node'))) {
if ($fb->get_loggedin_user()) {
if ($fb->api_client->users_isAppUser())
$front = $fb_canvas_data['front_added'];
else
$front = $fb_canvas_data['front_loggedin'];
}
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 (isset($original_uid) &&
$original_uid != $user->uid) {
// The user has changed, presumably fb_user.module recognized the facebookuser. We need to refresh canvas pages.
if (!(arg(0) == 'fb_app' && arg(1) == 'event')) {
// In order to ensure that drupal handles
// permissions properly, the user must make the request all over
// again. Skip this for the profile tab, as facebook does not allow
// redirects (or persistent session) there.
if ((fb_canvas_is_fbml() || fb_canvas_is_iframe()) &&
!fb_is_profile_tab()) {
$url = fb_canvas_fix_url(url(fb_scrub_urls($_REQUEST['q']), array('absolute' => TRUE)), $fb_app);
if (fb_verbose())
watchdog('fb_canvas', "User uid is now {$user->uid} (was {$original_uid}), redirecting canvas to $url to ensure permissions are correct."); // debug
$fb->redirect($url);
}
}
}
// The ?destination=... url param means something to drupal but also to facebook. If ?fb_canvas_destination=... is set, we honor that.
if (isset($_REQUEST['fb_canvas_destination'])) {
$_REQUEST['destination'] = $_REQUEST['fb_canvas_destination'];
}
// Give FBML themes a chance to render tabs.
if (fb_canvas_is_fbml()) {
_fb_canvas_menu_hack();
}
// 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 ($GLOBALS['fb_canvas_post_process']) {
$output = ob_get_contents();
ob_end_clean();
if (fb_canvas_is_fbml()) {
$output = fb_canvas_process($output, array('force_absolute_canvas' => TRUE));
}
elseif (fb_canvas_is_iframe()) {
$output = fb_canvas_process($output, array('add_target' => TRUE));
}
}
if (fb_canvas_handling_form() && $output) {
// Avoid infinite loop if we get called from drupal_goto.
fb_canvas_handling_form(FALSE);
// Special handling for forms submitted to Drupal from FBML canvas pages.
// Cache the results to show the user later.
$token = uniqid('fb_');
$cid = session_id() . "_$token";
cache_set($cid, $output, 'cache_page', time() + (60 * 5), drupal_get_headers()); // (60 * 5) == 5 minutes
$dest = 'http://apps.facebook.com/' . $fb_app->canvas . "/fb/form_cache/$cid";
// $fb->redirect($url); // Does not work!
// Preserve some URL parameters
$query = array();
foreach (array('fb_force_mode') as $key) {
if ($_REQUEST[$key])
$query[] = $key . '=' . $_REQUEST[$key];
}
// drupal_goto honors $_REQUEST['destination'], but we only want
// that when no errors occurred.
if (form_get_errors()) {
unset($_REQUEST['destination']);
if ($_REQUEST['edit'])
unset($_REQUEST['edit']['destination']);
}
if (fb_verbose() == 'extreme') {
watchdog('fb', "Storing cached form page $cid, then redirecting to $dest, query is " . implode('&', $query));
}
drupal_goto($dest, implode('&', $query), NULL, 303); // appears to work
}
if (fb_canvas_is_fbml() || fb_canvas_is_iframe()) {
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->redirect($app_destination);
}
}
}
if (isset($output)) {
print($output);
}
}
}
/**
* 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 = $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,
'theme_fbml' => 'fb_fbml',
'theme_iframe' => 'fb_fbml',
);
return $fb_canvas_data;
}
/**
* Implementation of hook_form_alter.
*/
function fb_canvas_form_alter(&$form, &$form_state, $form_id) {
// Add our settings to the fb_app edit form.
if (isset($form['fb_app_data']) && is_array($form['fb_app_data'])) {
$fb_app = $form['#fb_app'];
$fb_canvas_data = _fb_canvas_get_config($fb_app);
$form['fb_app_data']['fb_canvas'] = array(
'#type' => 'fieldset',
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#title' => t('Facebook canvas pages'),
'#description' => t('Settings which apply to canvas pages.',
array('!url' => 'http://developers.facebook.com/get_started.php?tab=anatomy#canvas')),
);
$form['fb_app_data']['fb_canvas']['require_login'] = array(
'#type' => 'radios',
'#title' => t('Require authorization'),
'#description' => t('Require authorization if you want Drupal for Facebook to call require_login() on every canvas page.'),
'#options' => array(
FB_CANVAS_OPTION_ALLOW_ANON => t('Allow anonymous visitors'),
FB_CANVAS_OPTION_REQUIRE_LOGIN => t('Require all users to authorize the application'),
),
'#default_value' => $fb_canvas_data['require_login'],
'#required' => TRUE,
);
$form['fb_app_data']['fb_canvas']['front_anonymous'] =
array('#type' => 'textfield',
'#title' => t('Front page when user is not logged in to facebook'),
'#description' => t('Leave blank to use the site-wide front page. See Public Canvas Pages.',
array('!link' => 'http://wiki.developers.facebook.com/index.php/Public_Canvas_Pages')),
'#default_value' => $fb_canvas_data['front_anonymous'],
);
$form['fb_app_data']['fb_canvas']['front_loggedin'] =
array('#type' => 'textfield',
'#title' => t('Front page when user is logged in to facebook, but is not a user of the app'),
'#description' => t('Leave blank to use the site-wide front page.'),
'#default_value' => $fb_canvas_data['front_loggedin'],
);
$form['fb_app_data']['fb_canvas']['front_added'] =
array('#type' => 'textfield',
'#title' => t('Front page for authorized users of this application'),
'#description' => t('Leave blank to use the site-wide front page.'),
'#default_value' => $fb_canvas_data['front_added'],
);
/* XXX menu code here needs updating to D6
// Allow primary links to be different on facebook versus the rest of the
// site. Code from menu_configure() in menu.module.
$primary = variable_get('menu_primary_links_source', 'primary-links');
$primary_options = array_merge($menu_options, array('' => t('