Saving Twitter Tweets to Nodes in Drupal 7 with hook_cron

On Cornell AAP's new site (http://aap.cornell.edu) one of the requirements was to show their Twitter tweets in different pages.  The tweets had to match the look and feel of the new site, and had to pull in new tweets periodically so I knew I had to use hook_cron. Tweets that have images also needed to be saved and clicking the Tweet's image takes the user the original image.

So I needed a feed from Twitter only available using their API.  Access to Twitter's API uses oauth so I had to first get consumer and tokens from Twitter then use the twitteroauth library to connect and grab the feed.  On the Drupal end, I had to create the Tweet content type and make the hook_cron that saves Tweets into nodes.  Steps including urls, sample code, etc:

Here's the result on their news stream page.

1. Create app on Twitter and get consumer and tokens

Go to http://dev.twitter.com, create the app, generate the token keys.  Save the consumer and tokens for step 3

2. Download twitteroauth and upload to server

Available at https://github.com/abraham/twitteroauth.  I uploaded to the sites/libraries folder. It might be better to upload it to the module that contains your hook_cron code - it's up to you.

3. Drupal 7: Create content type Tweet

Machine name: tweet

Fields (Name / Machine name / Field type)

  • Title / title
  • Body / body
  • Date / field_date / Date (Collect year, month, day, hour, minute time increment 1 minute)
  • Thumbnail Image / field_thumbnail / Image
  • Tweet ID / field_tweet_id / Text Field
  • Tweet Image URL / field_tweet_image_url

4. Drupal 7: Create hook_cron

This is the cron that checks for new tweets using the twitteroauth library with the consumer and token keys and secrets.  Only tweets since the last tweet id are returned from the user_timeline api call.  For each tweet, save as a node and set the last tweet id so the next time the cron runs it only gets the newest tweets.  See comments in the code below.

function aap_twitter_cron() {

  watchdog('aap_twitter', 'Twitter cron start.');  

  require_once(DRUPAL_ROOT . '/sites/all/libraries/twitteroauth/twitteroauth.php');

  $screenname = 'cornellaap';
  $count = 100;
  $since_id = variable_get('aap_twitter_since_id', '382556531398828033');
  $consumer_key = '1234567890';
  $consumer_secret = '1234567890';
  $access_token = '1234567890';
  $access_token_secret = '1234567890';

  $connection = new TwitterOAuth($consumer_key, $consumer_secret, $access_token, $access_token_secret);

  /*
  * options to send for the user_timeline api
  * see https://dev.twitter.com/docs/api/1.1/get/statuses/user_timeline
  * count: number of tweets to return
  * screenname: the twitter username to get the timeline for
  * since_id: return tweets since this tweet id
  */
  $options = array();
  $options[] = sprintf('count=%s', $count);
  $options[] = sprintf('screen_name=%s', $screenname);
  $options[] = sprintf('since_id=%s', $since_id);
  $tweets = $connection->get('https://api.twitter.com/1.1/statuses/user_timeline.json?' . implode('&', $options));

  /*
  * Loop through tweets and save them. 
  * Create the tweet node, set the title, body, field_date, and field_tweet_id fields.
  * If there is an image save it into the Drupal file system and also save
  * the original URL in field_tweet_image_url.
  */
  if (count($tweets)) {
    foreach($tweets as $id=>$tweet) {
      $image_url = '';
      $date = date('Y-m-d g:i:s', strtotime($tweet->created_at));
      $node = new stdClass();
      $node->type = 'tweet';
      node_object_prepare($node);
      $node->uid = 1;
      $node->language = LANGUAGE_NONE;
      $node->title = $tweet->text;
      $node->body[LANGUAGE_NONE][0]['value'] = $tweet->text;
      $node->field_date[LANGUAGE_NONE][0]['value'] = $date;
      $node->field_tweet_id[LANGUAGE_NONE][0]['value'] = $tweet->id;
      // save image
      if (isset($tweet->entities->media[0]) && isset($tweet->entities->media[0]->media_url)) {
        $dirpath = variable_get('file_public_path', conf_path() . '/files');
        drupal_mkdir("$dirpath/tweets");    
        $image_url = $tweet->entities->media[0]->media_url;
        $image_url_parts = explode('/', $image_url);
        $filename = $image_url_parts[count($image_url_parts) - 1];
        $file_info = system_retrieve_file($image_url, 'public://tweets/' . $filename, TRUE, FILE_EXISTS_REPLACE);
        if ($file_info->fid) {
          $node->field_thumbnail[LANGUAGE_NONE][0]['fid'] = $file_info->fid;
          $node->field_tweet_image_url[LANGUAGE_NONE][0]['value'] = $image_url;
          watchdog('aap_twitter', 'Saved tweet image ' . $filename);
        }
      }
      // save node
      if($node = node_submit($node)) {
        node_save($node);
        watchdog('aap_twitter', 'Saved tweet ' . $tweet->text);
      }
    }
    variable_set('aap_twitter_since_id', $tweets[0]->id);
    watchdog('aap_twitter', 'Saved last tweet id ' . $tweets[0]->id);
  }
  watchdog('aap_twitter', 'Twitter cron finished.');  
}