Parent Directory
|
Revision Log
|
Revision Graph
avoid use of dprint_r()
| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * @file |
| 5 | * |
| 6 | * Helpers for Facebook feeds |
| 7 | * (http://wiki.developers.facebook.com/index.php/New_Design_Feed_Wall) |
| 8 | */ |
| 9 | |
| 10 | // Facebook used to support multiple messages per bundle, now only one. |
| 11 | define('FB_FEED_LINES_PER_BUNDLE', 1); |
| 12 | define('FB_FEED_SHORTS_PER_BUNDLE', 1); |
| 13 | define('FB_FEED_ACTION_LINKS_PER_BUNDLE', 3); |
| 14 | |
| 15 | define('FB_FEED_NODE_TYPE_TEMPLATE', 'fb_feed_template'); |
| 16 | |
| 17 | define('FB_FEED_HOOK', 'fb_feed'); |
| 18 | define('FB_FEED_OP_TOKEN_ALTER', 'fb_feed_token_alter'); |
| 19 | |
| 20 | function fb_feed_init() { |
| 21 | drupal_add_js(drupal_get_path('module', 'fb_feed') . '/fb_feed.js'); |
| 22 | } |
| 23 | |
| 24 | function fb_feed_menu() { |
| 25 | $items = array(); |
| 26 | $items['fb_feed/register'] = array( |
| 27 | 'title' => 'Register template', |
| 28 | 'type' => MENU_CALLBACK, |
| 29 | 'access arguments' => array('adminster fb apps'), |
| 30 | 'page callback' => 'fb_feed_register_cb', |
| 31 | ); |
| 32 | $items['fb_feed/deactivate'] = array( |
| 33 | 'title' => 'Deactivate template', |
| 34 | 'type' => MENU_CALLBACK, |
| 35 | 'access arguments' => array('adminster fb apps'), |
| 36 | 'page callback' => 'drupal_get_form', |
| 37 | 'page arguments' => array('fb_feed_deactivate_confirm'), |
| 38 | ); |
| 39 | |
| 40 | $items['node/%fb_app_nid/fb_feed/templates'] = array( |
| 41 | 'title' => t('Feed Templates'), |
| 42 | 'type' => MENU_LOCAL_TASK, |
| 43 | 'access callback' => 'node_access', |
| 44 | 'access arguments' => array('update', 1), |
| 45 | 'page callback' => 'fb_feed_template_page', |
| 46 | 'page arguments' => array(1), |
| 47 | ); |
| 48 | |
| 49 | return $items; |
| 50 | } |
| 51 | |
| 52 | function fb_feed_deactivate_confirm($fb_app_nid, $bundle_id) { |
| 53 | $result = db_query("SELECT n.nid, n.title FROM {node} n LEFT JOIN {fb_feed_template} fft ON fft.nid = n.nid WHERE fft.fb_app_nid = %d AND fft.bundle_id = %f", |
| 54 | $fb_app_nid, $bundle_id); |
| 55 | $data = db_fetch_object($result); |
| 56 | if ($data->nid) { |
| 57 | $form['nid'] = array('#type' => 'hidden', '#value' => $data->nid); |
| 58 | $description = t('This will deactivate the template on Facebook. The template node will not be deleted.'); |
| 59 | $question = t('Really deactivate the !template_link template?', |
| 60 | array('!template_link' => l($data->title, 'node/'.$data->nid))); |
| 61 | } |
| 62 | else |
| 63 | $question = t('Really deactivate template bundle %bundle_id?', |
| 64 | array('%bundle_id' => $bundle_id)); |
| 65 | |
| 66 | $form['bundle_id'] = array('#type' => 'hidden', |
| 67 | '#value' => $bundle_id); |
| 68 | $form['fb_app_nid'] = array('#type' => 'hidden', |
| 69 | '#value' => $fb_app_nid); |
| 70 | |
| 71 | return confirm_form($form, $question, 'node/'.$fb_app_nid.'/fb_feed/templates', |
| 72 | $description); |
| 73 | } |
| 74 | |
| 75 | function fb_feed_deactivate_confirm_submit($form_id, $values) { |
| 76 | $success = fb_feed_deactivate_template($values['fb_app_nid'], $values['bundle_id']); |
| 77 | if ($success && $values['nid']) |
| 78 | db_query("UPDATE {fb_feed_template} SET bundle_id=0 WHERE nid=%d", |
| 79 | $values['nid']); |
| 80 | |
| 81 | if ($success) { |
| 82 | drupal_set_message(t('The template %bundle_id has been deactivated.', |
| 83 | array('%bundle_id' => $values['bundle_id']))); |
| 84 | } |
| 85 | else { |
| 86 | drupal_set_message(t('The template %bundle_id could not be deactivated.', |
| 87 | array('%bundle_id' => $values['bundle_id'])), 'error'); |
| 88 | } |
| 89 | return 'node/'.$values['fb_app_nid'].'/fb_feed/templates'; |
| 90 | } |
| 91 | |
| 92 | function fb_feed_deactivate_template($fb_app_nid, $bundle_id) { |
| 93 | $fb_app = fb_get_app(array('nid' => $fb_app_nid)); |
| 94 | $fb = fb_api_init($fb_app, FB_FBU_ANY); |
| 95 | if (!$fb) { |
| 96 | drupal_set_message(t('Facebook API failed to connect. Template could not be deactivated.', 'error')); |
| 97 | return FALSE; |
| 98 | } |
| 99 | else { |
| 100 | $result = $fb->api_client->feed_deactivateTemplateBundleByID($bundle_id); |
| 101 | fb_report_errors($fb, 'Error while deactivating template.'); |
| 102 | } |
| 103 | return $result; |
| 104 | } |
| 105 | |
| 106 | function fb_feed_register_cb($nid) { |
| 107 | $node = node_load($nid); |
| 108 | $bundle_id = fb_feed_register_template($node); |
| 109 | drupal_goto('node/'.$node->fb_app_nid.'/fb_feed/templates'); |
| 110 | } |
| 111 | |
| 112 | function fb_feed_template_page($node) { |
| 113 | $fb_app = $node->fb_app; |
| 114 | $registered = array(); |
| 115 | $unregistered = array(); |
| 116 | // Query all known templates |
| 117 | $result = db_query("SELECT n.nid, n.title, n.status, fft.bundle_id FROM {node} n LEFT JOIN {fb_feed_template} fft ON fft.nid = n.nid WHERE fft.nid IS NOT NULL"); |
| 118 | while ($data = db_fetch_object($result)) { |
| 119 | if ($data->bundle_id) { |
| 120 | $registered[$data->bundle_id] = $data; |
| 121 | } |
| 122 | else { |
| 123 | $unregistered[] = $data; |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | // Query facebook for a list of registered templates we know nothing about. |
| 128 | $fb = fb_api_init($fb_app, FB_FBU_ANY); |
| 129 | if ($fb) { |
| 130 | try { |
| 131 | $all = $fb->api_client->feed_getRegisteredTemplateBundles(); |
| 132 | |
| 133 | if (is_array($all)) |
| 134 | foreach ($all as $data) { |
| 135 | if (isset($registered[$data['template_bundle_id']])) { |
| 136 | $registered[$data['template_bundle_id']]->confirmed = $data; |
| 137 | } |
| 138 | else |
| 139 | $registered[$data['template_bundle_id']] = $data; |
| 140 | } |
| 141 | } |
| 142 | catch (Exception $e) { |
| 143 | //dpm($fb, "fb"); |
| 144 | //dpm($fb->api_client, "api_client"); |
| 145 | fb_log_exception($e, t('Failed to get template bundles.')); |
| 146 | drupal_set_message(t('This page may show more information if you configure an infinite session or Facebook Connect.')); |
| 147 | } |
| 148 | } |
| 149 | else { |
| 150 | drupal_set_message("Facebook API not available. Some options will not be shown. Possible infinite session configuration problem.", 'error'); |
| 151 | } |
| 152 | |
| 153 | // Display one table of registered templates and another of unregistered. |
| 154 | if (count($unregistered)) { |
| 155 | $rows = array(); |
| 156 | foreach ($unregistered as $data) { |
| 157 | $ops = array(l(t('register'), 'fb_feed/register/'.$data->nid)); |
| 158 | $row = array(l($data->title, 'node/'.$data->nid), |
| 159 | implode(' | ', $ops)); |
| 160 | $rows[] = $row; |
| 161 | } |
| 162 | $header = array(t('Unregistered Template'), t('Operations')); |
| 163 | $output .= theme('table', $header, $rows); |
| 164 | } |
| 165 | else { |
| 166 | $output .= '<p>' . t('No unregistered templates found.') . '</p>'; |
| 167 | } |
| 168 | if (count($registered)) { |
| 169 | $rows = array(); |
| 170 | foreach ($registered as $data) { |
| 171 | $ops = array(); |
| 172 | |
| 173 | if ($data->confirmed) |
| 174 | $ops[] = l(t('deactivate'), 'fb_feed/deactivate/'.$fb_app->nid.'/'.$data->bundle_id); |
| 175 | else if ($data->nid && $fb && is_array($all)) |
| 176 | $ops = array(l(t('re-register'), 'fb_feed/register/'.$data->nid)); |
| 177 | else if ($data->template_bundle_id) |
| 178 | $ops[] = l(t('deactivate'), 'fb_feed/deactivate/'.$fb_app->nid.'/'.$data['template_bundle_id']); |
| 179 | |
| 180 | |
| 181 | |
| 182 | if ($data->nid) |
| 183 | $title = l($data->title, 'node/'.$data->nid); |
| 184 | else |
| 185 | // Use a template learned from facebook. |
| 186 | $title = $data['one_line_story_templates'][0]; |
| 187 | if ($data->bundle_id) |
| 188 | $bundle_id = $data->bundle_id; |
| 189 | else |
| 190 | $bundle_id = $data['template_bundle_id']; |
| 191 | $row = array($title, |
| 192 | $bundle_id, |
| 193 | implode(' | ', $ops), |
| 194 | ); |
| 195 | $rows[] = $row; |
| 196 | } |
| 197 | $header = array(t('Registered Template'), t('Bundle ID'), t('Operations')); |
| 198 | $output .= theme('table', $header, $rows); |
| 199 | } |
| 200 | else { |
| 201 | $output .= '<p>' . t('No registered templates found.') . '</p>'; |
| 202 | } |
| 203 | |
| 204 | |
| 205 | return $output; |
| 206 | } |
| 207 | |
| 208 | /** |
| 209 | * hook_node_info. |
| 210 | */ |
| 211 | function fb_feed_node_info() { |
| 212 | return array(FB_FEED_NODE_TYPE_TEMPLATE => |
| 213 | array('name' => t('Facebook Template Bundle'), |
| 214 | 'module' => 'fb_feed', |
| 215 | 'description' => t('Templates for posting information to Facebook feeds.'), |
| 216 | 'help' => t('Configure the feed stories of your Facebook Application.'), |
| 217 | ), |
| 218 | ); |
| 219 | } |
| 220 | |
| 221 | /** |
| 222 | * Use same permissions as fb_app module. |
| 223 | */ |
| 224 | function fb_feed_access($op, $node) { |
| 225 | if (user_access('administer fb apps')) |
| 226 | return TRUE; |
| 227 | if ($op == 'create' && user_access('create fb apps')) |
| 228 | return TRUE; |
| 229 | else if ($op == 'update' || $op == 'delete') { |
| 230 | if ($node->uid == $user->uid && |
| 231 | user_access('edit own fb apps')) |
| 232 | return TRUE; |
| 233 | } |
| 234 | } |
| 235 | |
| 236 | function fb_feed_form(&$node, &$param) { |
| 237 | $form = array(); |
| 238 | $type = node_get_types('type', $node); |
| 239 | // We need to define form elements for the node's title and body. |
| 240 | $form['title'] = array('#type' => 'textfield', |
| 241 | '#title' => check_plain($type->title_label), |
| 242 | '#required' => TRUE, |
| 243 | '#default_value' => $node->title, |
| 244 | '#weight' => -5, |
| 245 | '#description' => t('Identifies the template bundle to site administrators.'), |
| 246 | ); |
| 247 | |
| 248 | $form['label'] = array('#type' => 'textfield', |
| 249 | '#title' => t('Label'), |
| 250 | '#required' => TRUE, |
| 251 | '#default_value' => $node->label, |
| 252 | '#description' => t('Used to refer to this template programmatically. Use only alphanumeric characters.<br/>When hosting an application on both dev and production servers, use the same labels. Bundle ids, apikeys and so on must change between servers, so custom code must rely on this label. On any single server, each label must be unique.'), |
| 253 | '#weight' => -5, |
| 254 | ); |
| 255 | |
| 256 | if ($type->body_label) { |
| 257 | $form['body_filter']['body'] = |
| 258 | array('#type' => 'textarea', |
| 259 | '#title' => check_plain($type->body_label), |
| 260 | '#default_value' => $node->body, |
| 261 | '#required' => FALSE, |
| 262 | '#description' => 'Not sure yet how this will be used.', |
| 263 | ); |
| 264 | $form['body_filter']['filter'] = filter_form($node->format); |
| 265 | } |
| 266 | |
| 267 | // Now we define the form elements specific to our node type. |
| 268 | |
| 269 | $options = fb_get_app_options(FALSE); |
| 270 | $form['fb_app_nid'] = |
| 271 | array('#type' => 'select', |
| 272 | '#title' => t('Application'), |
| 273 | '#default_value' => $values['fb_app_nid'], |
| 274 | '#options' => $options, |
| 275 | '#description' => t('Which application will use these templates?<br />'), |
| 276 | '#weight' => -5, |
| 277 | '#required' => TRUE, |
| 278 | ); |
| 279 | |
| 280 | $form['fb_feed_data'] = array('#tree' => TRUE, |
| 281 | '#weight' => -4, |
| 282 | ); |
| 283 | $form['fb_feed_data']['description'] = |
| 284 | array('#type' => 'markup', |
| 285 | '#value' => t('Read <a target=_blank href="!url">about template bundles</a> for more information.', |
| 286 | array('!url' => 'http://wiki.developers.facebook.com/index.php/Feed.registerTemplateBundle')), |
| 287 | ); |
| 288 | |
| 289 | $form['fb_feed_data']['example'] = |
| 290 | array('#type' => 'markup', |
| 291 | '#value' => t('Here\'s an example that produces a message like "<em>User Name</em> wrote about <em>something</em> on <em>application</em>," where <em>something</em> is the title of a node:<br/><em>{*actor*} wrote about {*fb-feed-canvas-node-link*} on {*fb-feed-canvas-app-link*}</em>'), |
| 292 | '#prefix' => '<p>', |
| 293 | '#suffix' => '</p>', |
| 294 | ); |
| 295 | |
| 296 | $form['fb_feed_data']['line'] = array('#type' => 'fieldset', |
| 297 | '#title' => t('One-line templates'), |
| 298 | '#description' => t('Note that one-line templates must begin with the {*actor*} token.'), |
| 299 | '#collapsible' => TRUE, |
| 300 | ); |
| 301 | $i = 0; |
| 302 | while ($i < FB_FEED_LINES_PER_BUNDLE) { |
| 303 | $form['fb_feed_data']['line'][$i] = |
| 304 | array('#type' => 'textfield', |
| 305 | '#title' => t('Additional one-line template'), |
| 306 | '#default_value' => $node->fb_feed_data['line'][$i], |
| 307 | ); |
| 308 | $i++; |
| 309 | } |
| 310 | $form['fb_feed_data']['line'][0]['#title'] = t('One-line template'); |
| 311 | $form['fb_feed_data']['line'][0]['#required'] = TRUE; |
| 312 | |
| 313 | |
| 314 | |
| 315 | |
| 316 | $form['fb_feed_data']['short'] = array('#type' => 'fieldset', |
| 317 | '#title' => t('Short templates'), |
| 318 | '#description' => t('Note that titles must begin with the {*actor*} token.'), |
| 319 | '#collapsible' => TRUE, |
| 320 | ); |
| 321 | |
| 322 | $i = 0; |
| 323 | while ($i < FB_FEED_SHORTS_PER_BUNDLE) { |
| 324 | $form['fb_feed_data']['short'][$i]['template_title'] = |
| 325 | array('#type' => 'textfield', |
| 326 | '#title' => t('Additional short template title'), |
| 327 | '#default_value' => $node->fb_feed_data['short'][$i]['template_title'], |
| 328 | ); |
| 329 | $form['fb_feed_data']['short'][$i]['template_body'] = |
| 330 | array('#type' => 'textarea', |
| 331 | '#title' => t('Additional short template body'), |
| 332 | '#default_value' => $node->fb_feed_data['short'][$i]['template_body'], |
| 333 | '#rows' => 2, |
| 334 | ); |
| 335 | $i++; |
| 336 | } |
| 337 | $form['fb_feed_data']['short'][0]['template_title']['#title'] = t('Short template title'); |
| 338 | $form['fb_feed_data']['short'][0]['template_body']['#title'] = t('Short template body'); |
| 339 | |
| 340 | |
| 341 | $i = 0; |
| 342 | while ($i < FB_FEED_ACTION_LINKS_PER_BUNDLE) { |
| 343 | $form['fb_feed_data']['action_links'][$i] = array( |
| 344 | '#type' => 'fieldset', |
| 345 | '#title' => t('Additional Action Link'), |
| 346 | '#description' => t('For additional information, see <a target=_blank href="!href">Action Links</a>.', |
| 347 | array('!href' => 'http://wiki.developers.facebook.com/index.php/Action_Links')), |
| 348 | '#collapsible' => TRUE, |
| 349 | '#collapsed' => $node->fb_feed_data['action_links'][$i]['text'] ? FALSE : TRUE, |
| 350 | ); |
| 351 | $form['fb_feed_data']['action_links'][$i]['text'] = array( |
| 352 | '#type' => 'textfield', |
| 353 | '#title' => t('Text'), |
| 354 | '#default_value' => $node->fb_feed_data['action_links'][$i]['text'], |
| 355 | ); |
| 356 | $form['fb_feed_data']['action_links'][$i]['href'] = array( |
| 357 | '#type' => 'textfield', |
| 358 | '#title' => t('Href'), |
| 359 | '#default_value' => $node->fb_feed_data['action_links'][$i]['href'], |
| 360 | ); |
| 361 | $i++; |
| 362 | } |
| 363 | $form['fb_feed_data']['action_links'][0]['#title'] = t('First Action Link'); |
| 364 | $form['fb_feed_data']['action_links'][0]['#collapsed'] = FALSE; |
| 365 | |
| 366 | // TODO: add action links http://wiki.developers.facebook.com/index.php/Feed.registerTemplateBundle |
| 367 | |
| 368 | if (module_exists('token')) { |
| 369 | $form['token_help'] = array('#type' => 'fieldset', |
| 370 | '#collapsible' => TRUE, |
| 371 | '#collapsed' => FALSE, |
| 372 | '#title' => t("Token help"), |
| 373 | '#description' => t('Facebook uses the special token <em>{*actor*}</em> for the user performing an action. Another special token is <em>{*target*}</em>, which should only be used by expert users, as Facebook often fails to publish messages with the <em>{*target*}</em> token.'), |
| 374 | ); |
| 375 | $form['token_help']['warning'] = array( |
| 376 | '#type' => 'markup', |
| 377 | '#value' => t('<strong>Bugs in FBJS may prevent token substitution from working on canvas pages.</strong> Facebook Connect pages are OK, but problems have been reported on FBML canvas pages when publishing messages with token substitution.'), |
| 378 | '#prefix' => '<p>', |
| 379 | '#suffix' => '</p>', |
| 380 | ); |
| 381 | foreach (array('node', 'comment', 'user', 'fb_app') as $type) { |
| 382 | $form['token_help'][$type] = |
| 383 | array('#type' => 'fieldset', |
| 384 | '#collapsible' => TRUE, |
| 385 | '#collapsed' => TRUE, |
| 386 | '#title' => t("!type tokens", array('!type' => $type)), |
| 387 | '#description' => theme('token_help', $type, "{*", "*}"), |
| 388 | ); |
| 389 | } |
| 390 | } |
| 391 | |
| 392 | |
| 393 | return $form; |
| 394 | } |
| 395 | |
| 396 | function fb_feed_validate($node) { |
| 397 | // TODO |
| 398 | // Ensure each label is unique. |
| 399 | } |
| 400 | |
| 401 | function fb_feed_register_template($node) { |
| 402 | |
| 403 | $fb_app = fb_get_app(array('nid' => $node->fb_app_nid)); |
| 404 | // Login to facebook as either the current user or the infinite session |
| 405 | if ($fb_app) { |
| 406 | $fb = fb_api_init($fb_app, FB_FBU_ANY); |
| 407 | if ($fb) { |
| 408 | // Clean up the data before sending to facebook. Send no empty templates. |
| 409 | $lines = array(); |
| 410 | foreach ($node->fb_feed_data['line'] as $line) { |
| 411 | if ($line) |
| 412 | $lines[] = $line; |
| 413 | } |
| 414 | $shorts = array(); |
| 415 | foreach ($node->fb_feed_data['short'] as $item) { |
| 416 | if ($item['template_title']) |
| 417 | $shorts[] = $item; |
| 418 | } |
| 419 | $full = array(); |
| 420 | if ($node->fb_feed_data['full']['template_title']) |
| 421 | $full = $node->fb_feed_data['full']; |
| 422 | |
| 423 | $action_links = $node->fb_feed_data['action_links']; |
| 424 | foreach ($action_links as $i => $data) { |
| 425 | if (!$data['text'] || !$data['href']) { |
| 426 | unset($action_links[$i]); |
| 427 | } |
| 428 | } |
| 429 | |
| 430 | if ($fb) { |
| 431 | try { |
| 432 | $bundle_id = |
| 433 | $fb->api_client->feed_registerTemplateBundle($lines, $shorts, $full, $action_links); |
| 434 | } |
| 435 | catch (Exception $e) { |
| 436 | fb_log_exception($e, t('Error attempting to register template bundle.'), $fb); |
| 437 | } |
| 438 | if ($bundle_id) |
| 439 | drupal_set_message(t('Registered template bundle %bundle_id with Facebook.', |
| 440 | array('%bundle_id' => $bundle_id))); |
| 441 | else |
| 442 | drupal_set_message(t('Failed to register the template.'), 'error'); |
| 443 | |
| 444 | if ($bundle_id && $node->nid) |
| 445 | db_query("UPDATE {fb_feed_template} fft SET bundle_id=%f WHERE nid=%d", |
| 446 | $bundle_id, $node->nid); |
| 447 | |
| 448 | return $bundle_id; |
| 449 | } |
| 450 | } |
| 451 | } |
| 452 | // TODO: report failure to connect to facebook api |
| 453 | drupal_set_message(t('Failed to connect to Facebook for application %app.', |
| 454 | array('%app' => $fb_app->title)), 'error'); |
| 455 | } |
| 456 | |
| 457 | function fb_feed_insert($node) { |
| 458 | |
| 459 | // Register the new template with facebook. |
| 460 | $bundle_id = fb_feed_register_template($node); |
| 461 | if (!$bundle_id) |
| 462 | // Show an error, but save the node anyway. |
| 463 | drupal_set_message(t('Failed to register template bundle with Facebook. This template bundle may not be used.'), 'error'); |
| 464 | |
| 465 | $data = serialize($node->fb_feed_data); |
| 466 | |
| 467 | // We're going to save the apikey, although it may be redundant with the |
| 468 | // fb_app_nid, so that we can detect any inconsistencies (i.e. the apikey |
| 469 | // has changed on us). |
| 470 | $fb_app = fb_get_app(array('nid' => $node->fb_app_nid)); |
| 471 | |
| 472 | db_query("INSERT INTO {fb_feed_template} (nid, fb_app_nid, label, apikey, bundle_id, fb_feed_data) VALUES (%d, %d, '%s', '%s', %f, '%s')", |
| 473 | $node->nid, $node->fb_app_nid, $node->label, $fb_app->apikey, $bundle_id, $data); |
| 474 | |
| 475 | if ($bundle_id) |
| 476 | watchdog('fb_feed', 'Registered Facebook feed template bundle %id for application %app', |
| 477 | array('%id' => $bundle_id, |
| 478 | '%app' => $fb_app->title, |
| 479 | )); |
| 480 | } |
| 481 | |
| 482 | function fb_feed_update($node) { |
| 483 | //dpm($node, "fb_feed_update"); |
| 484 | |
| 485 | // deactivate the previously registered bundle |
| 486 | if ($node->bundle_id) { |
| 487 | fb_feed_deactivate_template($node->fb_app_nid, $node->bundle_id); |
| 488 | unset($node->bundle_id); |
| 489 | } |
| 490 | |
| 491 | // Register the new template with facebook. |
| 492 | $bundle_id = fb_feed_register_template($node); |
| 493 | if (!$bundle_id) |
| 494 | // Show an error, but save the node anyway. |
| 495 | drupal_set_message(t('Failed to register template bundle with Facebook. This template bundle may not be used.'), 'error'); |
| 496 | |
| 497 | $data = serialize($node->fb_feed_data); |
| 498 | |
| 499 | // We're going to save the apikey, although it may be redundant with the |
| 500 | // fb_app_nid, so that we can detect any inconsistencies (i.e. the apikey |
| 501 | // has changed on us). |
| 502 | $fb_app = fb_get_app(array('nid' => $node->fb_app_nid)); |
| 503 | |
| 504 | db_query("UPDATE {fb_feed_template} SET fb_app_nid=%d, label='%s', apikey='%s', bundle_id=%f, fb_feed_data='%s' WHERE nid=%d", |
| 505 | $node->fb_app_nid, $node->label, $fb_app->apikey, $bundle_id, $data, $node->nid); |
| 506 | |
| 507 | if ($bundle_id) |
| 508 | watchdog('fb_feed', 'Updated Facebook feed template bundle %id for application %app', |
| 509 | array('%id' => $bundle_id, |
| 510 | '%app' => $fb_app->title, |
| 511 | )); |
| 512 | |
| 513 | } |
| 514 | |
| 515 | function fb_feed_delete($node) { |
| 516 | // TODO: deactivate the previously registered bundle |
| 517 | db_query('DELETE FROM {fb_feed_template} WHERE nid=%d', |
| 518 | $node->nid); |
| 519 | } |
| 520 | |
| 521 | function fb_feed_load($node) { |
| 522 | $data = db_fetch_array(db_query('SELECT fb_app_nid, label, apikey, bundle_id, fb_feed_data FROM {fb_feed_template} WHERE nid=%d', |
| 523 | $node->nid)); |
| 524 | $data['fb_feed_data'] = unserialize($data['fb_feed_data']); |
| 525 | return $data; |
| 526 | } |
| 527 | |
| 528 | // TODO: hook_nodeapi. React appropriately if fb_app apikey changes or is deleted. |
| 529 | |
| 530 | function fb_feed_view($node, $teaser=FALSE, $page=FALSE) { |
| 531 | $node = node_prepare($node, $teaser); |
| 532 | $fb_app = fb_get_app(array('nid' => $node->fb_app_nid)); |
| 533 | |
| 534 | if (!$node->bundle_id) |
| 535 | drupal_set_message(t('The template shown must be registered with Facebook before it can be used.'), 'error'); |
| 536 | |
| 537 | $items = array(t('Application') => l($fb_app->title, 'node/'.$fb_app->nid), |
| 538 | t('Label') => $node->label, |
| 539 | t('Template Bundle ID') => $node->bundle_id ? $node->bundle_id : '<em>'.t('Template bundle not registered') . '</em>', |
| 540 | ); |
| 541 | $items[t('One-line templates')] = implode("<br />\n", |
| 542 | array_map('check_plain', $node->fb_feed_data['line'])); |
| 543 | foreach ($node->fb_feed_data['short'] as $key => $template) { |
| 544 | if (is_array($template)) |
| 545 | $items[t('Short template %num', array('%num' => $key +1))] = |
| 546 | implode("<br />\n", array_map('check_plain', $node->fb_feed_data['short'][$key])); |
| 547 | } |
| 548 | |
| 549 | if ($node->fb_feed_data['full']['template_title']) { |
| 550 | $items[t('Full template')] = |
| 551 | implode("<br />\n", array_map('check_plain', $node->fb_feed_data['full'])); |
| 552 | } |
| 553 | $node->content['fb_feed'] = array('#value' => theme('dl', $items)); |
| 554 | return $node; |
| 555 | } |
| 556 | |
| 557 | |
| 558 | /** |
| 559 | * Publish a feed message via the Feed Dialog. This will prompt the |
| 560 | * user before writing to the feed, and this is Facebook's recommended |
| 561 | * technique. The other option is publishUserAction. |
| 562 | * |
| 563 | * Our approach here is like drupal_set_message. We save the data to |
| 564 | * the session, and show the user the dialog on the next page request. |
| 565 | */ |
| 566 | function fb_feed_show_dialog($label, $tokens, $options) { |
| 567 | if (!isset($_SESSION['fb_feed_dialogs'])) |
| 568 | $_SESSION['fb_feed_dialogs'] = array(); |
| 569 | |
| 570 | // Accept either label or template as first param. |
| 571 | if (is_object($label)) { |
| 572 | $template = $label; |
| 573 | } |
| 574 | else { |
| 575 | $template = fb_feed_get_template_by_label($label); |
| 576 | } |
| 577 | |
| 578 | if ($template) { |
| 579 | // Change token data structure. |
| 580 | if (is_object($tokens) && is_array($tokens->tokens)) { |
| 581 | foreach ($tokens->tokens as $i => $key) { |
| 582 | $fb_tokens[$key] = $tokens->values[$i]; |
| 583 | } |
| 584 | } |
| 585 | else { |
| 586 | $fb_tokens = $tokens; |
| 587 | } |
| 588 | |
| 589 | |
| 590 | if (!isset($_SESSION['fb_feed_dialogs'][$template->apikey])) { |
| 591 | $_SESSION['fb_feed_dialogs'][$template->apikey] = array(); |
| 592 | } |
| 593 | |
| 594 | $_SESSION['fb_feed_dialogs'][$template->apikey][] = array( |
| 595 | 'fb_feed_nid' => $template->nid, |
| 596 | 'apikey' => $template->apikey, |
| 597 | 'bundle_id' => $template->bundle_id, |
| 598 | 'tokens' => $fb_tokens, |
| 599 | 'options' => $options, |
| 600 | ); |
| 601 | } |
| 602 | else { |
| 603 | // TODO: log error. |
| 604 | } |
| 605 | } |
| 606 | |
| 607 | /** |
| 608 | * Get the data for one or more feed dialogs. Use this function in |
| 609 | * ajax callbacks, where you want to publish dialog(s) in response to |
| 610 | * javascript events. Json encode the result, and pass it to |
| 611 | * Fb_Feed.show_feed_dialog(). |
| 612 | */ |
| 613 | function fb_feed_get_show_dialog_data($fb_app = null) { |
| 614 | if (!$fb_app) |
| 615 | $fb_app = $GLOBALS['fb_app']; |
| 616 | |
| 617 | $data = $_SESSION['fb_feed_dialogs'][$fb_app->apikey]; |
| 618 | unset($_SESSION['fb_feed_dialogs'][$fb_app->apikey]); |
| 619 | return $data; |
| 620 | } |
| 621 | |
| 622 | |
| 623 | /** |
| 624 | * Implementation of hook_fb(). |
| 625 | */ |
| 626 | function fb_feed_fb($op, $data, &$return) { |
| 627 | if ($op == FB_OP_CONNECT_JS_INIT || $op == FB_OP_CANVAS_FBJS_INIT) { |
| 628 | // This is our chance to add feed dialog to the current page. |
| 629 | |
| 630 | if (isset($_SESSION['fb_feed_dialogs']) && |
| 631 | isset($_SESSION['fb_feed_dialogs'][$data['fb_app']->apikey])) { |
| 632 | // Use javascript to publish feed messages |
| 633 | foreach ($_SESSION['fb_feed_dialogs'][$data['fb_app']->apikey] as $d) { |
| 634 | |
| 635 | // Note that FB.Connect.ShowFeedDialog and Facebook.showFeedDialog take different parameters. Thanks, facebook! |
| 636 | |
| 637 | if ($op == FB_OP_CONNECT_JS_INIT) { |
| 638 | // http://wiki.developers.facebook.com/index.php/JS_API_M_FB.Connect.ShowFeedDialog |
| 639 | $args = array($d['bundle_id']); |
| 640 | foreach (array('template_data' => '{}', |
| 641 | 'target_ids' => 'null', |
| 642 | 'body_general' => 'null', |
| 643 | 'story_size' => 'null', |
| 644 | 'require_connect' => 'null', |
| 645 | 'callback' => 'null', |
| 646 | 'user_message_prompt' => 'null', |
| 647 | 'user_message' => 'null', |
| 648 | ) as $key => $default) { |
| 649 | if (isset($d['options'][$key])) { |
| 650 | if (in_array($key, array('require_connect', 'callback'))) |
| 651 | $args[] = $d['options'][$key]; // no json_encode |
| 652 | else if ($key == 'user_message' && is_string($d['options'][$key])) { |
| 653 | $args[] = '{value:' . json_encode($d['options'][$key]) . '}'; |
| 654 | } |
| 655 | else |
| 656 | $args[] = json_encode($d['options'][$key]); |
| 657 | } else |
| 658 | $args[] = $default; |
| 659 | } |
| 660 | $return[] = "FB.Connect.showFeedDialog(" . implode(',', $args) . ");"; |
| 661 | } |
| 662 | else if ($op == FB_OP_CANVAS_FBJS_INIT) { |
| 663 | // http://wiki.developers.facebook.com/index.php/Facebook.showFeedDialog |
| 664 | $args = array($d['bundle_id']); |
| 665 | foreach (array('template_data' => 'null', |
| 666 | 'body_general' => 'null', |
| 667 | 'target_id' => 'null', // note target_id int |
| 668 | 'continuation' => 'null', |
| 669 | 'user_message_prompt' => 'null', |
| 670 | 'user_message' => 'null', |
| 671 | ) as $key => $default) { |
| 672 | if (isset($d['options'][$key])) { |
| 673 | if (in_array($key, array('continuation'))) |
| 674 | $args[] = $d['options'][$key]; // no json_encode |
| 675 | else if ($key == 'user_message' && is_string($d['options'][$key])) { |
| 676 | $args[] = '{value:' . json_encode($d['options'][$key]) . '}'; |
| 677 | } |
| 678 | else |
| 679 | $args[] = json_encode($d['options'][$key]); |
| 680 | } else |
| 681 | $args[] = $default; |
| 682 | } |
| 683 | |
| 684 | $return[] = "Facebook.showFeedDialog(" . implode(",\n", $args) . ");"; |
| 685 | |
| 686 | } |
| 687 | } |
| 688 | //dpm($return, 'fb_feed_fb debug'); |
| 689 | |
| 690 | // remove displayed items from session |
| 691 | unset($_SESSION['fb_feed_dialogs'][$data['fb_app']->apikey]); |
| 692 | } |
| 693 | } |
| 694 | } |
| 695 | |
| 696 | |
| 697 | //// Feed Actions |
| 698 | function fb_feed_action_info() { |
| 699 | $items = array(); |
| 700 | $items['fb_feed_action_publish'] = array( |
| 701 | 'type' => 'fb_feed_action', |
| 702 | 'description' => t('Facebook Feed: publishUserAction'), |
| 703 | 'configurable' => TRUE, |
| 704 | // Include 'custom' so third-party modules can define their own triggers. |
| 705 | 'hooks' => array( |
| 706 | 'nodeapi' => array('delete', 'insert', 'update', 'view', 'custom'), |
| 707 | 'comment' => array('delete', 'insert', 'update', 'view', 'custom'), |
| 708 | 'user' => array('insert', 'update', 'delete', 'login', 'logout', 'custom'), |
| 709 | ), |
| 710 | ); |
| 711 | $items['fb_feed_action_show_dialog'] = array( |
| 712 | 'type' => 'fb_feed_action_show_dialog', |
| 713 | 'description' => t('Facebook Feed: show dialog'), |
| 714 | 'configurable' => TRUE, |
| 715 | // Include 'custom' so third-party modules can define their own triggers. |
| 716 | 'hooks' => array( |
| 717 | 'nodeapi' => array('delete', 'insert', 'update', 'view', 'custom'), |
| 718 | 'comment' => array('delete', 'insert', 'update', 'view', 'custom'), |
| 719 | 'user' => array('insert', 'update', 'delete', 'login', 'logout', 'custom'), |
| 720 | ), |
| 721 | ); |
| 722 | |
| 723 | |
| 724 | return $items; |
| 725 | } |
| 726 | |
| 727 | function fb_feed_get_template_options() { |
| 728 | $options = array(0 => t('<please choose>')); |
| 729 | $result = db_query(db_rewrite_sql("SELECT DISTINCT n.nid, n.title FROM {node} n WHERE n.type='%s' AND n.status=1"), FB_FEED_NODE_TYPE_TEMPLATE); |
| 730 | while ($data = db_fetch_object($result)) { |
| 731 | $options[$data->nid] = $data->title; |
| 732 | } |
| 733 | return $options; |
| 734 | } |
| 735 | |
| 736 | function fb_feed_action_publish_form($values) { |
| 737 | drupal_set_message(t('Note that Facebook recommends showFeedDialog over publishUserAction. Consider using the show feed dialog action instead.')); |
| 738 | // Allow user to choose amoung all available templates. |
| 739 | $options = fb_feed_get_template_options(); |
| 740 | $form['description'] = array('#value' => t('Note that this action will only succeed when executed from a Facebook canvas page when the user is logged in, or on non-canvas pages when the local user has authorized offline access. These are privacy restrictions enforced by the Facebook API.')); |
| 741 | $form['fb_feed_template_nid'] = |
| 742 | array('#type' => 'select', |
| 743 | '#title' => t('Template'), |
| 744 | '#default_value' => $values['fb_feed_template_nid'], |
| 745 | '#options' => $options, |
| 746 | '#description' => t('Which template will we be using?'), |
| 747 | '#required' => TRUE, |
| 748 | ); |
| 749 | |
| 750 | $form['token_enable'] = |
| 751 | array('#type' => 'checkbox', |
| 752 | '#title' => t('Use token replacement'), |
| 753 | '#default_value' => $values['token_enable'], |
| 754 | '#description' => t('Use token module for template substitution.'), |
| 755 | ); |
| 756 | |
| 757 | $form['hook_help'] = |
| 758 | array('#type' => 'markup', |
| 759 | '#value' => t('In addition to token replacement, <em>hook_fb_feed</em> will be called before Feed.publishUserAction is called. This hook gives you an oportunity to customize the parameters that will be passed to Facebook, for example to provide values for custom tokens in your template. Until further documentation is provided, you should look in the code for exactly how these functions are called.'), |
| 760 | '#prefix' => '<p>', |
| 761 | '#suffix' => '</p>', |
| 762 | ); |
| 763 | return $form; |
| 764 | } |
| 765 | |
| 766 | function fb_feed_action_publish_validate($form_id, $values) { |
| 767 | // TODO |
| 768 | } |
| 769 | |
| 770 | function fb_feed_action_publish_submit($form_id, $state) { |
| 771 | $items = array(); |
| 772 | foreach (array('fb_feed_template_nid', 'token_enable') as $key) { |
| 773 | $items[$key] = $state['values'][$key]; |
| 774 | } |
| 775 | return $items; |
| 776 | } |
| 777 | |
| 778 | function fb_feed_action_publish(&$context, $values = array()) { |
| 779 | //dpm(func_get_args(), 'fb_actions_minifeed'); |
| 780 | |
| 781 | // Get the objects we're acting upon. |
| 782 | $objects = array(); |
| 783 | if ($values['hook'] == 'nodeapi') { |
| 784 | $objects['node'] = $values['node']; |
| 785 | } |
| 786 | else if ($values['hook'] == 'comment') { |
| 787 | $objects['comment'] = $values['comment']; |
| 788 | $objects['node'] = node_load($values['comment']->nid); |
| 789 | } |
| 790 | else if ($values['hook'] == 'user') { |
| 791 | $account = $values['user']; |
| 792 | $objects['user'] = $account; |
| 793 | } |
| 794 | |
| 795 | // Get the template |
| 796 | $template = node_load($values['fb_feed_template_nid']); |
| 797 | // TODO: Sanity check that bundle has been registered with Facebook. |
| 798 | // And the app |
| 799 | $fb_app = fb_get_app(array('nid' => $template->fb_app_nid)); |
| 800 | $objects['fb_app'] = $fb_app; |
| 801 | // TODO: Sanity check that apikeys match. |
| 802 | |
| 803 | |
| 804 | // Log into facebook as the current user. |
| 805 | if ($GLOBALS['fb_app'] && ($fb_app->nid = $GLOBALS['fb_app']->nid)) |
| 806 | // We're in a canvas page for the desired app. We're already logged in. |
| 807 | $fb = $GLOBALS['fb']; |
| 808 | else { |
| 809 | global $user; |
| 810 | // Must log in to publish user action. This will only work if the user |
| 811 | // have authorized us for offline access. |
| 812 | $fbu = fb_get_fbu($user->uid, $fb_app); |
| 813 | if ($fbu) { |
| 814 | $fb = fb_api_init($fb_app, $fbu); |
| 815 | } |
| 816 | } |
| 817 | |
| 818 | // It's possible we have an $fb, but session may not be valid. TODO: find a |
| 819 | // way to test this? |
| 820 | if ($fb) { |
| 821 | |
| 822 | // We need to pass a bunch of parameters to Feed.publishUserAction. |
| 823 | $params = array('bundle_id' => $template->bundle_id, |
| 824 | 'tokens' => array(), |
| 825 | 'target_ids' => array(), |
| 826 | 'body_general' => '', |
| 827 | 'do_publish' => TRUE, |
| 828 | ); |
| 829 | $options = array('fb_feed_template' => $template); |
| 830 | |
| 831 | if ($values['token_enable']) { |
| 832 | // Use tokens for every kind of object we know about |
| 833 | foreach (array('node', 'comment', 'user', 'fb_app') as $type) { |
| 834 | if ($objects[$type]) { |
| 835 | $toks = token_get_values($type, $objects[$type], FALSE, $options); |
| 836 | //watchdog('fb_feed_debug', "token_get_values($type) returned " . print_r($toks, 1)); |
| 837 | if ($toks && is_array($toks->tokens)) { |
| 838 | foreach ($toks->tokens as $i => $key) |
| 839 | $params['tokens'][$key] = $toks->values[$i]; |
| 840 | } |
| 841 | } |
| 842 | } |
| 843 | } |
| 844 | |
| 845 | // Use naming conventions to allow tokens to provide every parameter. |
| 846 | if ($params['tokens']['target_ids']) |
| 847 | $params['target_ids'][] = $params['tokens']['target_ids']; |
| 848 | if ($params['tokens']['body_general']) |
| 849 | $params['body_general'] = $params['tokens']['body_general']; |
| 850 | |
| 851 | // Invoke a hook so that other modules have a chance to modify the params before we pass them to facebook. |
| 852 | $params = fb_feed_invoke($fb_app, FB_FEED_OP_TOKEN_ALTER, |
| 853 | $params, array('fb_feed_template' => $template, |
| 854 | 'objects' => $objects, |
| 855 | 'context' => $context)); |
| 856 | |
| 857 | if (fb_verbose()) { |
| 858 | watchdog('fb_feed', "Publish user action, app is %app, bundle is %bundle_id, params are !params.", |
| 859 | array('%app' => $fb_app->title, |
| 860 | '%bundle_id' => $template->bundle_id, |
| 861 | '!params' => print_r($params, 1))); |
| 862 | } |
| 863 | if (is_array($params['tokens']) && $params['do_publish']) { |
| 864 | if (is_array($params['target_ids'])) |
| 865 | $target_ids = implode(',', $params['target_ids']); |
| 866 | else |
| 867 | $target_ids = $params['target_ids']; |
| 868 | |
| 869 | try { |
| 870 | // http://wiki.developers.facebook.com/index.php/Feed.publishUserAction |
| 871 | //if (FALSE) // disabled for debugging |
| 872 | $fb->api_client->feed_publishUserAction($template->bundle_id, |
| 873 | json_encode($params['tokens']), |
| 874 | $target_ids, |
| 875 | $params['body_general']); |
| 876 | } catch (Exception $e) { |
| 877 | // We can get a lot of "Feed action limit reached" exceptions. So |
| 878 | // only log if fb_verbose is true. |
| 879 | if ($e->getCode() != 341 || fb_verbose()) |
| 880 | fb_log_exception($e, t('Failed to publish user action')); |
| 881 | } |
| 882 | } |
| 883 | } |
| 884 | |
| 885 | } |
| 886 | |
| 887 | |
| 888 | // show feed dialog action |
| 889 | |
| 890 | function fb_feed_action_show_dialog_form($values) { |
| 891 | // Allow user to choose from all available templates. |
| 892 | $options = fb_feed_get_template_options(); |
| 893 | $form['description'] = array( |
| 894 | '#value' => t('Note that this action will only succeed when executed from a Facebook canvas page or Facebook Connect page when the user is logged in. These are privacy restrictions enforced by the Facebook API.')); |
| 895 | $form['fb_feed_template_nid'] = array( |
| 896 | '#type' => 'select', |
| 897 | '#title' => t('Template'), |
| 898 | '#default_value' => $values['fb_feed_template_nid'], |
| 899 | '#options' => $options, |
| 900 | '#description' => t('Which template will we be using?'), |
| 901 | '#required' => TRUE, |
| 902 | ); |
| 903 | |
| 904 | $form['token_enable'] = array( |
| 905 | '#type' => 'checkbox', |
| 906 | '#title' => t('Use token replacement'), |
| 907 | '#default_value' => $values['token_enable'], |
| 908 | '#description' => t('Use token module for template substitution. <br/><strong>Bugs in FBJS may cause cryptic errors when publishing feed dialogs on canvas pages.</strong> This feature will work with Facebook Connect. On FBML canvas pages your mileage may vary. If problems arise, leave this unchecked and implement hook_fb_feed_show_dialog_alter() instead.'), |
| 909 | ); |
| 910 | |
| 911 | $form['user_message_prompt'] = array( |
| 912 | '#type' => 'textfield', |
| 913 | '#title' => t('Prompt'), |
| 914 | '#description' => t('The label (which could be in the form of a question) that appears above the text box on the Feed form next to the Facebook-provided default, "Write Something..."'), |
| 915 | '#default_value' => $values['user_message_prompt'], |
| 916 | ); |
| 917 | |
| 918 | $form['hook_help'] = array( |
| 919 | '#type' => 'markup', |
| 920 | '#value' => t('In addition to token replacement, <em>drupal_alter(\'fb_feed_show_dialog\', ...)</em> will be called before fb_feed_show_dialog. This hook gives your custom module an opportunity to change any values before they are passed to Facebook\'s API.'), |
| 921 | '#prefix' => '<p>', |
| 922 | '#suffix' => '</p>', |
| 923 | ); |
| 924 | return $form; |
| 925 | } |
| 926 | |
| 927 | function fb_feed_action_show_dialog_validate($form_id, $values) { |
| 928 | // TODO |
| 929 | } |
| 930 | |
| 931 | function fb_feed_action_show_dialog_submit($form_id, $state) { |
| 932 | $items = array(); |
| 933 | foreach (array('fb_feed_template_nid', 'token_enable', 'user_message_prompt') as $key) { |
| 934 | $items[$key] = $state['values'][$key]; |
| 935 | } |
| 936 | return $items; |
| 937 | } |
| 938 | |
| 939 | function fb_feed_action_show_dialog(&$context, $values = array()) { |
| 940 | // Get the template |
| 941 | $template = node_load($values['fb_feed_template_nid']); |
| 942 | // Params we will pass to alter hook, then to fb_feed_show_dialog |
| 943 | $params = array( |
| 944 | 'template' => $template, |
| 945 | 'tokens' => array(), |
| 946 | 'options' => array( |
| 947 | 'user_message_prompt' => $values['user_message_prompt'], |
| 948 | ), |
| 949 | 'cancel' => FALSE, // Allow alter hook to cancel dialog. |
| 950 | ); |
| 951 | |
| 952 | // Get the objects we're acting upon. |
| 953 | $objects = array(); |
| 954 | if ($values['hook'] == 'nodeapi') { |
| 955 | $objects['node'] = $values['node']; |
| 956 | $params['options']['user_message'] = check_plain($objects['node']->body); |
| 957 | } |
| 958 | else if ($values['hook'] == 'comment') { |
| 959 | $objects['comment'] = $values['comment']; |
| 960 | $objects['node'] = node_load($values['comment']->nid); |
| 961 | $params['options']['user_message'] = check_plain($objects['comment']->comment); |
| 962 | } |
| 963 | else if ($values['hook'] == 'user') { |
| 964 | $account = $values['user']; |
| 965 | $objects['user'] = $account; |
| 966 | } |
| 967 | |
| 968 | // TODO: Sanity check that bundle has been registered with Facebook. |
| 969 | // And the app |
| 970 | $fb_app = fb_get_app(array('nid' => $template->fb_app_nid)); |
| 971 | $objects['fb_app'] = $fb_app; |
| 972 | // TODO: Sanity check that apikeys match. |
| 973 | |
| 974 | |
| 975 | if ($values['token_enable']) { |
| 976 | // Use tokens for every kind of object we know about |
| 977 | foreach (array('node', 'comment', 'user', 'fb_app') as $type) { |
| 978 | if ($objects[$type]) { |
| 979 | $toks = token_get_values($type, $objects[$type], FALSE, $options); |
| 980 | //watchdog('fb_feed_debug', "token_get_values($type) returned " . print_r($toks, 1)); |
| 981 | if ($toks && is_array($toks->tokens)) { |
| 982 | foreach ($toks->tokens as $i => $key) |
| 983 | $params['options']['template_data'][$key] = $toks->values[$i]; |
| 984 | } |
| 985 | } |
| 986 | } |
| 987 | } |
| 988 | |
| 989 | |
| 990 | // Invoke a hook so that other modules have a chance to modify the params before we pass them to facebook. |
| 991 | drupal_alter('fb_feed_show_dialog', $params, |
| 992 | array('context' => $context, |
| 993 | 'objects' => $objects)); |
| 994 | |
| 995 | if (!$params['cancel']) { |
| 996 | fb_feed_show_dialog($params['template'], $params['tokens'], $params['options']); |
| 997 | } |
| 998 | |
| 999 | } |
| 1000 | |
| 1001 | |
| 1002 | |
| 1003 | |
| 1004 | |
| 1005 | |
| 1006 | |
| 1007 | |
| 1008 | /** |
| 1009 | * Implementation of hook_fb_feed |
| 1010 | */ |
| 1011 | function fb_feed_fb_feed($fb_app, $op, &$return, $data) { |
| 1012 | if ($op == FB_FEED_OP_TOKEN_ALTER) { |
| 1013 | // In this hook, we have a chance to add tokens before a user action is |
| 1014 | // published. |
| 1015 | if ($return['tokens']['nid'] && $return['tokens']['title'] && |
| 1016 | $return['tokens']['fb-app-url']) { |
| 1017 | // Add a link to a canvas page |
| 1018 | $return['tokens']['fb-feed-node-link'] = l($return['tokens']['title-raw'], |
| 1019 | $return['tokens']['fb-app-url'].'/node/'.$return['tokens']['nid'], |
| 1020 | array(), NULL, NULL, NULL, TRUE); |
| 1021 | } |
| 1022 | if ($return['tokens']['fb-app-title'] && $return['tokens']['fb-app-url']) { |
| 1023 | $return['tokens']['fb-feed-app-link'] = l($return['tokens']['fb-app-title'], |
| 1024 | $return['tokens']['fb-app-url'], |
| 1025 | array(), NULL, NULL, NULL, TRUE); |
| 1026 | } |
| 1027 | } |
| 1028 | } |
| 1029 | |
| 1030 | /** |
| 1031 | * Invoke hook_fb_feed. |
| 1032 | */ |
| 1033 | function fb_feed_invoke($fb_app, $op, $return = NULL, $data = NULL) { |
| 1034 | foreach (module_implements(FB_FEED_HOOK) as $name) { |
| 1035 | $function = $name . '_' . FB_FEED_HOOK; |
| 1036 | $function($fb_app, $op, $return, $data); |
| 1037 | } |
| 1038 | return $return; |
| 1039 | } |
| 1040 | |
| 1041 | /** |
| 1042 | * Helper to get feed data programatically. |
| 1043 | */ |
| 1044 | function fb_feed_get_template_by_label($label) { |
| 1045 | $result = db_query("SELECT fbf.*, n.title FROM {fb_feed_template} fbf INNER JOIN {node} n ON n.nid = fbf.nid WHERE n.status=1 AND fbf.label='%s'", |
| 1046 | $label); |
| 1047 | return db_fetch_object($result); |
| 1048 | } |
| 1049 | |
| 1050 | /** |
| 1051 | * Implementation of hook_fb_feed_show_dialog_alter() |
| 1052 | * |
| 1053 | * This is called before a feed dialog is shown. Here we provide some |
| 1054 | * of the most commonly used tokens. |
| 1055 | * |
| 1056 | */ |
| 1057 | function fb_feed_fb_feed_show_dialog_alter(&$params, $data) { |
| 1058 | // TODO: this function is canvas-centric. Need to add Facebook Connect support. |
| 1059 | |
| 1060 | // Uncomment the dpm() function to see what's getting passed to this function. Useful when implementing/debugging. |
| 1061 | //dpm(func_get_args(), "fb_feed_fb_feed_show_dialog_alter"); |
| 1062 | |
| 1063 | // Due to bugs in facebook's FBJS, we can't rely on token substitution. So we must provide values for all our feed template tokens here. |
| 1064 | |
| 1065 | if ($fb_app = $data['objects']['fb_app']) { |
| 1066 | if ($fb_app->canvas) { |
| 1067 | $params['options']['template_data']['fb-feed-canvas-app-link'] = |
| 1068 | l($fb_app->title, |
| 1069 | 'http://apps.facebook.com/'.$fb_app->canvas); |
| 1070 | } |
| 1071 | |
| 1072 | // Image TODO |
| 1073 | /** |
| 1074 | $params['options']['template_data']['images'] = array( |
| 1075 | array('src' => IMAGE URL HERE XXX |
| 1076 | 'href' => 'http://apps.facebook.com/' . $fb_app->canvas, |
| 1077 | ), |
| 1078 | ); |
| 1079 | **/ |
| 1080 | // $data['objects']['node'] is set if the Action was triggered by a node event. |
| 1081 | if ($node = $data['objects']['node']) { |
| 1082 | if ($fb_app->canvas) { |
| 1083 | $params['options']['template_data']['fb-feed-canvas-node-link'] = |
| 1084 | l($node->title, |
| 1085 | 'http://apps.facebook.com/'.$fb_app->canvas . '/node/' . $node->nid); |
| 1086 | } |
| 1087 | $params['options']['template_data']['fb-feed-node-teaser'] = |
| 1088 | check_plain($node->teaser); |
| 1089 | |
| 1090 | < |