'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(''))); $form['fb_app_data']['fb_canvas']['menu_primary_links_source'] = array( '#type' => 'select', '#title' => t('Source for the primary links'), '#default_value' => $fb_canvas_data['primary_links'], '#options' => $primary_options, '#tree' => FALSE, '#description' => t('Your application can have primary links different from those used elsewhere on your site.'), ); $secondary_options = array_merge($menu_options, array('' => t(''))); $form['fb_app_data']['fb_canvas']['menu_secondary_links_source'] = array( '#type' => 'select', '#title' => t('Source for the secondary links'), '#default_value' => $fb_canvas_data['secondary_links'], '#options' => $secondary_options, '#tree' => FALSE, '#description' => t('If you select the same menu as primary links then secondary links will display the appropriate second level of your navigation hierarchy.'), ); */ // Override themes $themes = system_theme_data(); ksort($themes); $theme_options[0] = t('System default'); foreach ($themes as $theme) { $theme_options[$theme->name] = $theme->name; } $form['fb_app_data']['fb_canvas']['theme_fbml'] = array( '#type' => 'select', '#title' => t('Theme for FBML pages'), '#description' => t('Choose only a theme that is FBML-aware.'), '#options' => $theme_options, '#required' => TRUE, '#default_value' => $fb_canvas_data['theme_fbml'], ); $form['fb_app_data']['fb_canvas']['theme_iframe'] = array( '#type' => 'select', '#title' => t('Theme for iframe pages'), '#description' => t('Choose only a facebook-aware theme'), '#options' => $theme_options, '#required' => TRUE, '#default_value' => $fb_canvas_data['theme_iframe'], ); } // We will send all form submission directly to us, not via // apps.facebook.com/whatever. if (fb_canvas_is_fbml()) { //dpm($form, "fb_canvas_form_alter($form_id)"); // debug // We're in a facebook callback if (!isset($form['fb_canvas_form_handler'])) { // Use the form data structure to keep track of whether data is // posted directly to us, via absolute URL, or instead via // relative URL on apps.facebook.com/... $form['fb_canvas_form_handler'] = array( '#action_fb' => $form['#action'], '#action_local' => _fb_canvas_make_form_action_local($form['#action']), ); // This helper function allows third-party modules to control // where the post goes. By default use local server. fb_canvas_form_action_via_facebook($form, FALSE); } // Drupal includes wacky markup for javascript junk in node forms. It // makes things look terrible in FBML. It only works when javascript is // enabled and it should have been implemented to degrade gracefully, but // it wasn't. if (isset($form['body_field'])) { unset($form['body_field']['teaser_js']); unset($form['body_field']['teaser_include']); } } } /** * Call this from your form_alter hook to prevent changes to the * form's default action. */ function fb_canvas_form_action_via_facebook(&$form, $use_facebook = TRUE) { if (isset($form['fb_canvas_form_handler'])) { if ($use_facebook) { $form['#action'] = $form['fb_canvas_form_handler']['#action_fb']; $form['fb_canvas_form_handler']['_fb_handling_form'] = array( '#value' => FALSE, '#type' => 'hidden'); } else { $form['#action'] = $form['fb_canvas_form_handler']['#action_local']; $form['fb_canvas_form_handler']['_fb_handling_form'] = array( '#value' => TRUE, '#type' => 'hidden'); } } } /** * Implementation of hook_footer(). * * Invoke FB_OP_CANVAS_FBJS_INIT, allowing other modules to insert * FBJS to the current page. */ function fb_canvas_footer($main = 0) { if (fb_canvas_is_fbml()) { // Add FBJS only to FBML pages. global $_fb, $_fb_app; $data = array('fb' => $_fb, 'fb_app' => $_fb_app); $extra = fb_invoke(FB_OP_CANVAS_FBJS_INIT, $data, array()); if (count($extra)) { $extra_js = implode("\n", $extra); fb_add_js('', ''); // prime javascript drupal_add_js($extra_js, 'inline', 'fbml'); } } } function fb_canvas_is_fbml() { global $_fb, $_fb_app; if ($_fb && $_fb_app) { // Facebook events are not canvas pages if (arg(0) == 'fb_app' && arg(1) == 'event') return FALSE; else return ($_fb->in_fb_canvas() || fb_canvas_handling_form()); } } function fb_canvas_is_iframe() { global $_fb, $_fb_app; if ($_fb && $_fb_app) { return ($_fb->in_frame() && !fb_canvas_is_fbml()); } } function fb_canvas_handling_form($value = NULL) { global $_fb; // Test whether a form has been submitted via facebook canvas page. if ($_fb && isset($_REQUEST['_fb_handling_form'])) { $result = $_REQUEST['_fb_handling_form']; } if (isset($value)) { $_REQUEST['_fb_handling_form'] = $value; } return $result; } // This may need work function _fb_canvas_make_form_action_local($action = NULL) { //dpm($action, "_fb_canvas_make_form_action_local"); global $base_path; if (!isset($action)) { $action = $_GET['q']; } // If action is fully qualified, do not change it if (strpos($action, ':')) return $action; // I'm not sure where the problem is, but sometimes actions have two question marks. I.e. // /htdocs/?app=foo&q=user/login?destination=comment/reply/1%2523comment-form // Here we replace 3rd (or more) '?' with '&'. $parts = explode('?', $action); if (count($parts) > 2) { $action = array_shift($parts) . '?' . array_shift($parts); $action .= '&' . implode('&', $parts); } $relative = url(''); $absolute = url('', array('absolute' => TRUE)); global $_fb_app; if (strpos($action, FB_SETTINGS_APP_LABEL)) { $action = $absolute . substr($action, strlen($relative)); } elseif (strpos($action, $relative) === 0) { // Replace relative action with absolute. // Include fb settings // TODO: FB_SETTINGS_PAGE_TYPE $action = $absolute . FB_SETTINGS_APP_LABEL . '/' . $_fb_app->label . '/' . substr($action, strlen($relative)); } //dpm($action, '_fb_canvas_make_form_action_local returning'); return $action; //drupal_set_message("form action now " . "http://".$_SERVER['HTTP_HOST']. $action); // debug //return "http://".$_SERVER['HTTP_HOST']. $action; } /** * Uses $_fb->redirect on canvas pages, otherwise drupal_goto. */ function fb_canvas_goto($path) { global $_fb, $_fb_app; if ($_fb && (fb_canvas_is_fbml() || fb_canvas_is_iframe())) { $url = fb_canvas_fix_url(url($path, array('absolute' => TRUE)), $_fb_app); $_fb->redirect($url); } else { drupal_goto($path); } exit; } /** * Convert a local fully qualified path to a facebook app path. This needs to * be used internally, to fix drupal_gotos upon form submission. Third party * modules should not need to call this. */ function fb_canvas_fix_url($url, $fb_app) { global $base_url; $patterns[] = "|{$base_url}/" . FB_SETTINGS_APP_LABEL . "/{$fb_app->label}/|"; // Here we hard-wire apps.facebook.com. Is there an API to get that? $replacements[] = "http://apps.facebook.com/{$fb_app->canvas}/"; // Fully qualified paths. $patterns[] = "|" . url('', array('absolute' => TRUE)) . "|"; $replacements[] = "http://apps.facebook.com/{$fb_app->canvas}/"; // Page type helps themes support multiple iframes. $patterns[] = "|" . FB_SETTINGS_PAGE_TYPE . "/[^/]*/|"; $replacements[] = ""; // Facebook will prepend "appNNN_" all our ids $patterns[] = "|#([^\?]*)|"; $replacements[] = "#app{$fb_app->id}_$1"; $url = preg_replace($patterns, $replacements, $url); return $url; } // This dates back to 5.x code and may no longer work! function fb_canvas_primary_links() { global $_fb_app; $mid = 0; if ($_fb_app) { $fb_app_data = fb_get_app_data($_fb_app); $fb_canvas_data = $fb_app_data['fb_canvas']; $mid = $fb_canvas_data['primary_links']; } if ($mid) return menu_primary_links(1, $mid); else return menu_primary_links(); } // This dates back to 5.x code and may no longer work! function fb_canvas_secondary_links() { global $_fb_app; if ($_fb_app) { $fb_app_data = fb_get_app_data($_fb_app); $fb_canvas_data = $fb_app_data['fb_canvas']; $mid1 = $fb_canvas_data['primary_links']; $mid2 = $fb_canvas_data['secondary_links']; } if ($mid2) { if ($mid2 == $mid1) return menu_primary_links(2, $mid2); else return menu_primary_links(1, $mid2); } else return menu_secondary_links(); } /** * This function uses regular expressions to convert links on canvas pages * to URLs that begin http://apps.facebook.com/... * * Call this method from themes when producing either FBML or iframe canvas * pages. This is a relatively expensive operation. Its unfortunate that we * must do it on every page request. However to the best of my knowledge, * Drupal provides no better way. * * In Drupal 7.x, there should be a way to alter URLs before they are * rendered. That could provide a more efficient solution. Until * then we are stuck with this. * * @param $output is the page (or iframe block) about to be returned. * * @param $options - 'add_target' will cause target=_top to be added * when producing an iframe. 'force_absolute_canvas' will turn * relative urls for canvas pages into absolute, for use on profile * tabs. * */ function fb_canvas_process($output, $options = array()) { global $base_path, $base_url; global $_fb, $_fb_app; $patterns = array(); $replacements = array(); if ($_fb) { $base_before_rewrite = ''; $rewrite_options = array(); $base = $base_path . fb_url_outbound_alter($base_before_rewrite, $rewrite_options, ''); // short URL with rewrite applied. if (fb_canvas_is_fbml()) { //dpm($output, "before fb_canvas_process"); // We're producing FBML for a canvas page /* TODO: $output['logo'] is not being processed properly by these patterns. fb_canvas_process() returns '/sites/all/themes/fb_fbml/logo.png' and Facebook complains "Relative URLs not allowed here" */ // Fix for relative images $absolute_base = url('', array('absolute' => TRUE)); $patterns[] = "|src=\"{$base}|"; $replacements[] = "src=\"$absolute_base"; if (isset($options['force_absolute_canvas']) && $options['force_absolute_canvas']) { // Change links to use canvas on Facebook // Links ending in #something: $patterns[] = "|=\"{$base}([^\"]*#)|"; $replacements[] = "=\"http://apps.facebook.com/{$_fb_app->canvas}/$1app{$_fb_app->id}_"; // Other links $patterns[] = "|=\"{$base}|"; $replacements[] = "=\"http://apps.facebook.com/{$_fb_app->canvas}/"; } else { // Change links to use canvas on Facebook // Links ending in #something: $patterns[] = "|=\"{$base}([^\"]*#)|"; $replacements[] = "=\"/{$_fb_app->canvas}/$1app{$_fb_app->id}_"; // Other links $patterns[] = "|=\"{$base}|"; $replacements[] = "=\"/{$_fb_app->canvas}/"; } // Change paths to files to fully qualified URLs. This matches relative // URLs that do not include the canvas (that is, not matched by previous // patterns). if ($base_path != "/{$_fb_app->canvas}/") { $patterns[] = '|="'. $base_path . "(?!{$_fb_app->canvas})|"; $replacements[] = '="'. $base_url .'/'; } // Experimental! Change 1234@facebook to an tag. This is our // default user name convention when creating new users. Ideally, this // would be accomplished with something like: // http://drupal.org/node/102679. In the meantime, this may help for // canvas pages only. // Regexp avoids "1234@facebook" (surrounded by quotes) because // that can appear in forms and FBML tags. Also avoids // 1234@facebook.com, which can also appear in forms because it // is used in authmaps. TODO: investigate the efficiency of // this regexp (and/or make it optional) $patterns[] = '|(?'; // Drupal has a habit of adding ?destination=... to some URLs. // And Facebook for no good reason screws up when you do that. $patterns[] = "|href=\"([^\"]*)\?(.*)(destination)=|"; $replacements[] = 'href="$1?$2fb_canvas_destination='; } elseif (fb_canvas_is_iframe()) { // Add target=_top so that entire pages do not appear within an iframe. // TODO: make these pattern replacements more sophisticated, detect whether target is already set. if (isset($options['add_target']) && $options['add_target']) { // Add target=_top to all links $patterns[] = "|canvas}/"; } else { // Add target=_top to only external links $patterns[] = "|]*)href=\"([^:\"]*):|"; $replacements[] = " array( 'arguments' => array( 'fbu' => NULL, 'object' => NULL, 'orig_username' => NULL, ), ), 'fb_canvas_fbml_user_picture' => array( 'arguments' => array( 'fbu' => NULL, 'account' => NULL, 'orig' => NULL, ), ), ); } /** * Implementation of hook_theme_registry_alter(). * * Wrap original theme functions in our overrides. */ function fb_canvas_theme_registry_alter(&$theme_registry) { // Ideally, we'd do this only on themes which will certainly be used for FBML canvas pages. if ($theme_registry['username']['type'] == 'module') { // Override theme_username $theme_registry['fb_canvas_username_orig'] = $theme_registry['username']; $theme_registry['username'] = array( 'arguments' => array('object' => NULL), 'function' => 'fb_canvas_theme_username_override', 'type' => 'module', ); } if ($theme_registry['user_picture']['type'] == 'module') { // Override theme_user_picture $theme_registry['fb_canvas_user_picture_orig'] = $theme_registry['user_picture']; $theme_registry['user_picture'] = array( 'arguments' => array('account' => NULL), 'function' => 'fb_canvas_theme_user_picture_override', 'type' => 'module', ); } } /** * Build tabs in facebook-aware theme. */ function _fb_canvas_menu_hack() { if (fb_canvas_is_fbml()) { // We have to go out of our way here to theme the tabs. // The code in menu.inc that themes them is complex, // incomprehensible, and tangles the theme layer with the logic // layer. It doesn't help that the same theme functions are called // for tabs as are called for all other menus. So we use a global // to keep track of what we're doing. global $_fb_canvas_state; $_fb_canvas_state = 'tabs'; // Why does a call to menu_tab_root_path theme the tabs? I have no // idea, but it does and caches the result. menu_tab_root_path(); $_fb_canvas_state = NULL; } } /** * Our replacement for theme('username', ...) */ function fb_canvas_theme_username_override($object) { $orig = theme('fb_canvas_username_orig', $object); // Make no changes to non-FBML pages. if (fb_canvas_is_fbml() && ($fbu = fb_get_object_fbu($object))) { // Theme the username with FBML, using original username as backup. return theme('fb_canvas_fbml_username', $fbu, $object, $orig); } else { return $orig; } } /** * Theme FBML markup for username. */ function theme_fb_canvas_fbml_username($fbu, $object, $orig) { if (!$fbu) return $orig; $wrap_pre = ''; $wrap_post = ''; if ($object->uid && user_access('access user profiles')) { // Provide link if local account. $wrap_pre = $wrap_pre . ''; $wrap_post = '' . $wrap_post; $ifcantsee = 'ifcantsee="' . addslashes(check_plain($object->name)) . '"'; } $fbml = ""; return $wrap_pre . $fbml . $wrap_post; } /** * Our replacement for theme('user_picture', ...) */ function fb_canvas_theme_user_picture_override($object) { $orig = theme('fb_canvas_user_picture_orig', $object); // Respect Drupal's profile pic, if uploaded. if (isset($object->picture) && $object->picture) { return $orig; } // Make no changes to non-FBML pages. if (fb_canvas_is_fbml() && ($fbu = fb_get_object_fbu($object))) { // Theme the username with FBML, using original username as backup. return theme('fb_canvas_fbml_user_picture', $fbu, $object, $orig); } else { return $orig; } } /** * Theme FBML markup for user_picture. */ function theme_fb_canvas_fbml_user_picture($fbu, $object, $orig) { if (!$fbu) return $orig; $fbml = ""; $wrap_pre = ''; $wrap_post = ''; if ($object->uid && user_access('access user profiles')) { // Provide link if local account. $wrap_pre = $wrap_pre . ''; $wrap_post = '' . $wrap_post; } return $wrap_pre . $fbml . $wrap_post; }