Newer
Older
Dave Cohen
committed
<?php
/**
* @file
* Support for Facebook Connect features
* Note that Facebook connect will work properly only with themes that are
* Facebook Connect aware.
*/
Dave Cohen
committed
define('FB_CONNECT_VAR_PRIMARY', 'fb_connect_primary_label');
Dave Cohen
committed
define('FB_CONNECT_VAR_THEME_USERNAME_1', 'fb_connect_theme_username_1');
define('FB_CONNECT_VAR_THEME_USERNAME_2', 'fb_connect_theme_username_2');
define('FB_CONNECT_VAR_THEME_USERPIC_1', 'fb_connect_theme_userpic_1');
define('FB_CONNECT_VAR_THEME_USERPIC_2', 'fb_connect_theme_userpic_2');
Dave Cohen
committed
/**
* Implements hook_menu().
Dave Cohen
committed
*/
function fb_connect_menu() {
$items = array();
Dave Cohen
committed
$items[FB_PATH_ADMIN . '/fb_connect'] = array(
'title' => 'Facebook Connect',
'description' => 'Configure Facebook Connect',
'page callback' => 'drupal_get_form',
'page arguments' => array('fb_connect_admin_settings'),
'access arguments' => array(FB_PERM_ADMINISTER),
'file' => 'fb_connect.admin.inc',
'type' => MENU_LOCAL_TASK,
return $items;
}
/**
* Prepare for fbConnect use. Because a single Drupal might support
* multiple apps, we don't know in advance which is the fbConnect app.
*/
function fb_connect_app_init($fb_app) {
if (isset($GLOBALS['_fb_app']) &&
$GLOBALS['_fb_app']->apikey != $fb_app->apikey) {
// If we're in an iframe, only support connect for the iframe app.
return;
}
if ($fb = fb_api_init($fb_app)) {
$fbu = $fb->getUser();
if ($fbu &&
(!isset($GLOBALS['_fb_app']) || $GLOBALS['_fb_app']->apikey != $fb_app->apikey)) {
// The user has authorized the app and we now know something about them. Use a hook to trigger the actions of other modules.
Dave Cohen
committed
fb_invoke(FB_OP_APP_IS_AUTHORIZED, array(
'fbu' => $fbu,
'fb_app' => $fb_app,
'fb' => $fb));
// Remember which app we've initialized.
_fb_connect_set_app($fb_app);
_fb_connect_add_js($fb_app, $fb);
return $fb;
/**
* Helper function for other modules to know page is connected.
* Note that this may return data on connect pages and in iframe apps
* (depending on how iframe is configured).
*/
function fb_connect_get_app() {
return _fb_connect_set_app();
}
function _fb_connect_set_app($fb_app = NULL) {
$cache = &drupal_static(__FUNCTION__);
if (isset($fb_app)) {
$cache = $fb_app;
}
return $cache;
}
Dave Cohen
committed
/**
* Implements hook_fb().
Dave Cohen
committed
*/
function fb_connect_fb($op, $data, &$return) {
if ($op == FB_OP_CURRENT_APP && !$return && !fb_is_canvas()) {
Dave Cohen
committed
// This will cause fb.module to set the global $_fb when user is logged in via fbConnect.
if ($id = variable_get(FB_VAR_ID, NULL)) {
// Use $conf['fb_id'] if set in settings.php.
$return = fb_get_app(array('id' => $id));
}
elseif ($apikey = variable_get(FB_VAR_APIKEY, NULL)) { // Deprecated. Use fb_id instead.
$return = fb_get_app(array('apikey' => $apikey));
}
elseif ($label = variable_get(FB_CONNECT_VAR_PRIMARY, NULL)) {
Dave Cohen
committed
$return = fb_get_app(array('label' => $label));
Dave Cohen
committed
}
}
// Init Facebook javascript for primary app
_fb_connect_add_js($data['fb_app'], $data['fb']);
Dave Cohen
committed
// Include our admin hooks.
if (fb_is_fb_admin_page()) {
module_load_include('inc', 'fb_connect', 'fb_connect.admin');
Dave Cohen
committed
}
Dave Cohen
committed
/**
* This wrapper function around drupal_add_js() ensures that our
* settings are added once and only once when needed.
Dave Cohen
committed
*/
function _fb_connect_add_js($fb_app, $fb) {
$just_once = &drupal_static(__FUNCTION__);
if (fb_is_tab())
// Tabs are FBML.
return;
drupal_add_js(array(
'fb_connect' => array(
'front_url' => url('<front>'),
'fbu' => fb_facebook_user(),
),
), 'setting');
drupal_add_js(drupal_get_path('module', 'fb_connect') . '/fb_connect.js');
// If we are not the global $_fb_app
if ($fb_app) {
$settings = fb_js_settings();
if (!isset($settings['fb_init_settings']['apiKey']) ||
$settings['fb_init_settings']['apiKey'] != $fb_app->apikey) {
// Ensure JS initializes with the proper apikey. We may reach this if
// there is no "primary" app.
// @TODO fb.module should have a helper to make this cleaner.
$settings['fb_init_settings']['apiKey'] = $fb_app->apikey;
$settings['fb_init_settings']['session'] = $fb->getSession();
fb_js_settings('apikey', $fb_app->apikey);
fb_js_settings('fbu', fb_facebook_user($fb));
fb_js_settings('fb_init_settings', $settings['fb_init_settings']);
//$js = drupal_add_js(array('fb' => fb_js_settings()), 'setting');
// fb.module will add settings to footer.
/**
* Default markup for our login block.
*/
function _fb_connect_block_login_defaults() {
return array('anon_not_connected' => array(
'title' => t('Facebook Connect'),
'body' => array('value' => '<fb:login-button perms="!perms" v="2">Connect</fb:login-button>'),
),
'user_not_connected' => array(
'title' => t('Facebook Connect'),
'body' => array('value' => '<fb:login-button perms="!perms" v="2">Connect</fb:login-button>'),
),
'connected' => array(
'title' => t('Facebook Connect'),
// Logout commented out, because drupal has logout link.
'body' => array('value' => '<fb:profile-pic uid=!fbu></fb:profile-pic><!--<fb:login-button autologoutlink=true></fb:login-button>-->'),
/**
* Implements hook_block_info().
*/
function fb_connect_block_info() {
$items = array();
foreach (fb_get_all_apps() as $fb_app) {
$d = 'login_' . $fb_app->label;
$items[$d] = array(
'info' => t('Facebook Connect Login to !app',
array('!app' => $fb_app->title)),
);
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
return $items;
}
/**
* Implements hook_block_configure().
*/
function fb_connect_block_configure($delta = '') {
$orig_defaults = _fb_connect_block_login_defaults();
$defaults = variable_get('fb_connect_block_' . $delta, $orig_defaults);
$form['config'] = array('#tree' => TRUE);
// Settings for each user status that we can detect.
foreach (array('anon_not_connected', 'user_not_connected', 'connected') as $key) {
$form['config'][$key] = array(
'#type' => 'fieldset',
// title and description below
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$form['config'][$key]['title'] = array(
'#type' => 'textfield',
'#title' => t('Default title'),
'#default_value' => $defaults[$key]['title'],
);
$textformat = isset($defaults[$key]['body']['format']) ? $defaults[$key]['body']['format'] : 'full_html';
$form['config'][$key]['body'] = array(
'#type' => 'text_format',
'#title' => t('Body'),
'#base_type' => 'textarea',
'#format' => $textformat,
'#default_value' => $defaults[$key]['body']['value'],
);
$form['config'][] = array(
'#markup' => "<p><strong>Be sure to select a format that allows XFBML tags!</strong> (That is, use <em>Full HTML</em> or <em>PHP code</em> (PHP Filter module must be enabled), rather than <em>Filtered HTML</em>.)</p>",
'#weight' => -10,
);
$form['config']['anon_not_connected']['#title'] = t('Anonymous user, not connected');
$form['config']['anon_not_connected']['#description'] = t('Settings when local user is Anonymous, and not connected to Facebook. Typically a new account will be created when the user clicks the connect button.');
$form['config']['anon_not_connected']['body']['#description'] = t('Suggestion: %default .', array('%default' => $orig_defaults['anon_not_connected']['body']['value']));
$form['config']['user_not_connected']['#title'] = t('Registered user, not connected');
$form['config']['user_not_connected']['#description'] = t('Settings when local user is registered, and not connected to Facebook. Typically the facebook id will be linked to the local id after the user clicks the connect button.');
$form['config']['user_not_connected']['body']['#description'] = t('Suggestion: %default .', array('%default' => $orig_defaults['user_not_connected']['body']['value']));
$form['config']['connected']['#title'] = t('Connected user');
Dave Cohen
committed
$form['config']['connected']['#description'] = t('Settings when local user is connected to Facebook. You may render facebook\'s logout button, and/or information about the user. Consider using <a target="_blank" href="!xfbml_url">XFBML</a> such as <fb:name uid=!fbu></fb:name> or <fb:profile-pic uid=!fbu></fb:profile-pic>', array('!xfbml_url' => 'http://wiki.developers.facebook.com/index.php/XFBML'));
$form['config']['connected']['body']['#description'] = t('Note that <strong>!fbu</strong> will be replaced with the user\'s facebook id.<br/>Suggestion: %default .', array('%default' => $orig_defaults['connected']['body']['value']));
return $form;
}
/**
* Implements hook_block_save().
*/
function fb_connect_block_save($delta = '', $edit = array()) {
variable_set('fb_connect_block_' . $delta, $edit['config']);
}
function fb_connect_block_view($delta = '') {
if (!fb_is_tab()) {
// Hide block on tabs, where the $fbu is actually the page, not the user.
if (strpos($delta, 'login_') === 0) {
// Login block
$label = substr($delta, 6); // length of 'login_'
$fb_app = fb_get_app(array('label' => $label));
if ($fb_app &&
($fb = fb_connect_app_init($fb_app))) {
$fbu = $fb->getUser();
//_fb_connect_add_js($fb_app); moved to fb_connect_app_init()
$base = drupal_get_path('module', 'fb_connect');
$config = variable_get('fb_connect_block_' . $delta, _fb_connect_block_login_defaults());
$key = 'connected';
elseif ($GLOBALS['user']->uid >= 1) {
$key = 'user_not_connected';
$key = 'anon_not_connected';
$subject = $config[$key]['title'];
$content = $config[$key]['body']['value'];
// substitute fbu
$content = str_replace('!fbu', $fbu, $content);
// substitute perms
$perms = array();
drupal_alter('fb_required_perms', $perms);
$content = str_replace('!perms', implode(',', $perms), $content);
// Filter output according to settings in block configuration
$subject = check_plain($subject);
if (isset($config[$key]['body']['format'])) {
$content = check_markup($content, $config[$key]['body']['format'], '', FALSE);
$block = array(
'subject' => $subject,
'content' => $content,
);
return $block;
Dave Cohen
committed
}
}
/**
* Helper returns configuration for this module, on a per-app basis.
*/
function _fb_connect_get_config($fb_app) {
$fb_app_data = fb_get_app_data($fb_app);
$config = isset($fb_app_data['fb_connect']) ? $fb_app_data['fb_connect'] : array();
// Merge in defaults
$config += array(
);
return $config;
}
/**
* Implements hook_form_alter().
*/
function fb_connect_form_alter(&$form, &$form_state, $form_id) {
// Add our settings to the fb_app edit form.
Dave Cohen
committed
$fb_app = $form['#fb_app'];
$form['fb_app_data']['fb_connect'] = array(
'#type' => 'fieldset',
'#title' => 'Facebook connect',
'#tree' => TRUE,
'#collapsible' => TRUE,
// "Primary" will be initialized on every non-canvas page.
Dave Cohen
committed
$primary_label = variable_get(FB_CONNECT_VAR_PRIMARY, NULL);
$form['fb_app_data']['fb_connect']['primary'] = array(
'#type' => 'checkbox',
'#title' => t('Primary'),
'#description' => t('Initialize fbConnect javascript on all (non-canvas) pages. If this site supports multiple Facebook Apps, this may be checked for at most one.'),
Dave Cohen
committed
'#default_value' => isset($fb_app->label) && ($primary_label == $fb_app->label),
Dave Cohen
committed
if (($primary_label) && ($primary_label != $fb_app->label)) {
$form['fb_app_data']['fb_connect']['primary']['#description'] .= '<br/>' .
Dave Cohen
committed
t('Note that checking this will replace %app as the primary Facebook Connect app.', array('%app' => $primary_label));
$form['buttons']['submit']['#submit'][] = 'fb_connect_app_submit';
/**
* Submit callback. Sets or unsets "primary" app.
*/
Dave Cohen
committed
function fb_connect_app_submit($form, &$form_state) {
$values = $form_state['values'];
$label = $values['label'];
$data = $values['fb_app_data']['fb_connect'];
if ($data['primary']) {
variable_set(FB_CONNECT_VAR_PRIMARY, $label);
drupal_set_message(t('%label is the primary Facebook Connect application.', array('%label' => $label)));
}
elseif ($label == variable_get(FB_CONNECT_VAR_PRIMARY, NULL)) {
Dave Cohen
committed
// This app was the primary one, but the user has unchecked it.
/**
* Implements hook_theme_registry_alter().
*
* Override theme functions for things that can be displayed using
* XFBML. Currently overriding username and user_picture. We rename
* the original entries, as we will use them for users without
* javascript enabled.
*
* This hook is not well documented. Who knows what its supposed to
* return? No doubt this will need updating with each new version of
* Drupal.
*/
function fb_connect_theme_registry_alter(&$theme_registry) {
Dave Cohen
committed
// Ideally, we'd do this only on themes which will certainly be used for facebook connect pages.
if (variable_get(FB_CONNECT_VAR_THEME_USERNAME_2, TRUE) ||
(variable_get(FB_CONNECT_VAR_THEME_USERNAME_1, TRUE) &&
$theme_registry['username']['type'] == 'module')) {
Dave Cohen
committed
// Re-register the original theme function under a new name.
$theme_registry['fb_connect_username_orig'] = $theme_registry['username'];
// Override theme username
$theme_registry['username'] = array(
'variables' => array('object' => NULL),
Dave Cohen
committed
'function' => 'fb_connect_theme_username_override',
'type' => 'module',
'theme path' => drupal_get_path('module', 'fb_connect'), // something is needed here but it isn't used
Dave Cohen
committed
);
}
if (variable_get(FB_CONNECT_VAR_THEME_USERPIC_2, TRUE) ||
(variable_get(FB_CONNECT_VAR_THEME_USERPIC_1, TRUE) &&
$theme_registry['user_picture']['type'] == 'module')) {
Dave Cohen
committed
// Re-register the original theme function under a new name.
$theme_registry['fb_connect_user_picture_orig'] = $theme_registry['user_picture'];
// Override theme username
$theme_registry['user_picture'] = array(
'variables' => array('account' => NULL),
Dave Cohen
committed
'function' => 'fb_connect_theme_user_picture_override',
'type' => 'module',
'theme path' => drupal_get_path('module', 'fb_connect'), // something is needed here but it isn't used
Dave Cohen
committed
);
}
}
/**
* Our replacement for theme('user_picture', ...)
*/
function fb_connect_theme_user_picture_override($variables) {
$account = $variables['account'];
// Markup without fb_connect.
$orig = theme('fb_connect_user_picture_orig', array('account' => $account));
Dave Cohen
committed
// Respect Drupal's profile pic, if uploaded.
if (isset($account->picture) && $account->picture) {
return $orig;
}
if ($fbu = fb_get_object_fbu($account)) {
$output = theme('fb_user_picture', array(
'fbu' => $fbu,
'account' => $account,
'orig' => $orig,
));
else {
$output = $orig;
}
return $output;
}
/**
* Our replacement for theme('username', ...)
*/
function fb_connect_theme_username_override($variables) {
$account = $variables['account'];
$orig = theme('fb_connect_username_orig', $variables);
if ($fbu = fb_get_object_fbu($account)) {
Dave Cohen
committed
// Theme the username with XFBML, using original username as backup.
return theme('fb_username', array(
'fbu' => $fbu,
'account' => $account,
'orig' => $orig,
));
return $orig;