Create a simple Twitter feed block with Drupal Aggregator and Views

Twitter feed

I'm back blogging about Drupal as I've been really busy lately. This is my 3rd post from the past 2 years (I ain't lazy, just busy studying =D). Anyway, in this article I'll be writing about how to create a simple Twitter feed block with Drupal that can be customised (almost) anyway you want it.

The screenshot on your right shows how the final output will look like. Taken from my homepage. Notice the random coloured Twitter tags and usernames.

First of all, install the 2 required modules; latest Drupal's Aggregator and Views.
Notice that I'm using 3.x-dev, but you shouldn't be using it unless you know your way around. Download the latest stable version from here. I was using 3.x-dev because there was a bug with View's header, footer, and empty text not showing up.

Modules

Navigate to admin/content/aggregator/add/feed and add a new feed. Give it a name/identifier and the URL to your Twitter timeline RSS. Once you have created this new feed, click on Update items for it to fetch the latest feeds.

Add feed

Next, we'll dive into the fun part. Create a new View for the feed you have just created. Copy my exported Views settings from here and (Update: Refer to my comment below for updated Views export data for Drupal 7) import to your Drupal site using the Import tool from Views UI. From here you can change those defined settings such as title, header, and footer text, etc. There's one more thing you need to edit on this Views before enabling the block. Click on Style settings, choose the setting Theme. Edit the Row style theme output. Copy the PHP codes into the recommended file names, then upload to your theme's directory. Click on Rescan template files then hit OK.

Enable the newly created Twitter block from Views, move it to a block region.

For the coloured Twitter tags and username, edit the View template file you have just created. Right above the line <?php print $field->content; ?>, place the following code above that. The inline comments in the code below explains on what the code does.

// Generate random colour for span tags later.
$codes = '1234567890abcdef';
$colour_codes = array();
// Generate 6 random colours for used in tags, randomised later.
for ($i = 0; $i < 6; $i++) {
  $colour_code = '#';
  for ($j = 0; $j < 6; $j++) {
    // We don't want bright colours (that starts with 'f').
    if ($j == 0) {
      $pos = mt_rand(0, 14);
    } else {
      $pos = mt_rand(0, 15);
    }
    $colour_code .= $codes[$pos];
  }
  $colour_codes[] = $colour_code;
}

$content = $field->content;
// Convert plain text links to actual links.
$content = filter_filter('process', 2, -1, $content);
// Remove "ktleow: " from feeds.
$content = str_replace('ktleow: ', '', $content);

// Explode data to array for later use. See below.
$content = explode(' ', $content);
// Look for matches of '#' and '@' twitter tags and wrap them with <span>.
foreach ($content as $key => $val) {
  if (preg_match('/^@/', $val)) {
    $content[$key] = '<span class="twitter-user" style="color: ' . $colour_codes[array_rand($colour_codes)] . '">' . $val . '</span>';
  }
  if (preg_match('/^#/', $val)) {
    $content[$key] = '<span class="twitter-tag" style="color: ' . $colour_codes[array_rand($colour_codes)] . '">' . $val . '</span>';
  }
}

$field->content = $content;

This should do it, now preview your newly created Twitter feed block! Should you have any questions or feedback, please drop me a comment below. Thanks!

20 comments for 'Create a simple Twitter feed block with Drupal Aggregator and Views'

Elias's picture

I follow exact your above steps...but it doesn't seem to work for me!
On the feed aggregator page I tried to update my item ... but an error message appeared telling " The feed from "myFeedTitle" seems to be broken, because of error "-60 Operation timed out"."

On the other hand I checked twitter api and i think that twitter stopped supporting direct rss feed ...http://goo.gl/SgGG8... However I see on your site that you have this twitter feed. Pls help... what am i doing wrong!!!

Elder Brother's picture

This is opening my eyes to a bunch of useful stuff besides the Twitter functionality, for which I'm much obliged.

I'm making the views template overrides for removing the twitter handle at the start of the feed and (trying) to return the active links from plain text. However, 'filter_filter' seems to have been depreciated in D7, so just wondering if you know how you would go about achieving the same thing now.

Many thanks,

Will.

admin's picture

Dear Elder Brother,

You are right, filter_filter() function has been depreceated in Drupal 7.

The new function is check_markup()

Change the line to the following, it should work =)

$content = check_markup($content, 'filtered_html');

Good luck!

timeth's picture

Thanks for this article Leow. I want to try using it on my site but the link to your exported Views settings leads to a 'Page not found' error :(

admin's picture

Oooops this was a very old article for Drupal 6. I had upgraded my site to D7 and i think i lost that file.

Anyway here's my exported view settings for my current twitter block >>>

$view = new view;
$view->name = 'twitter';
$view->description = '';
$view->tag = 'default';
$view->base_table = 'aggregator_item';
$view->human_name = 'Twitter';
$view->core = 7;
$view->api_version = '3.0-alpha1';
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
/* Display: Master */
$handler = $view->new_display('default', 'Master', 'default');
$handler->display->display_options['title'] = 'Twitter';
$handler->display->display_options['access']['type'] = 'none';
$handler->display->display_options['cache']['type'] = 'none';
$handler->display->display_options['query']['type'] = 'views_query';
$handler->display->display_options['query']['options']['query_comment'] = FALSE;
$handler->display->display_options['exposed_form']['type'] = 'basic';
$handler->display->display_options['pager']['type'] = 'some';
$handler->display->display_options['pager']['options']['items_per_page'] = '5';
$handler->display->display_options['pager']['options']['offset'] = '0';
$handler->display->display_options['style_plugin'] = 'list';
$handler->display->display_options['row_plugin'] = 'fields';
$handler->display->display_options['row_options']['hide_empty'] = 1;
/* Footer: Global: Text area */
$handler->display->display_options['footer']['area']['id'] = 'area';
$handler->display->display_options['footer']['area']['table'] = 'views';
$handler->display->display_options['footer']['area']['field'] = 'area';
$handler->display->display_options['footer']['area']['empty'] = TRUE;
$handler->display->display_options['footer']['area']['content'] = '<a href="http://twitter.com/ktleow">&raquo; follow me on twitter</a>';
$handler->display->display_options['footer']['area']['format'] = 'full_html';
/* Field: Aggregator: Body */
$handler->display->display_options['fields']['description']['id'] = 'description';
$handler->display->display_options['fields']['description']['table'] = 'aggregator_item';
$handler->display->display_options['fields']['description']['field'] = 'description';
$handler->display->display_options['fields']['description']['label'] = '';
$handler->display->display_options['fields']['description']['alter']['alter_text'] = 0;
$handler->display->display_options['fields']['description']['alter']['make_link'] = 0;
$handler->display->display_options['fields']['description']['alter']['absolute'] = 0;
$handler->display->display_options['fields']['description']['alter']['external'] = 0;
$handler->display->display_options['fields']['description']['alter']['replace_spaces'] = 0;
$handler->display->display_options['fields']['description']['alter']['nl2br'] = 0;
$handler->display->display_options['fields']['description']['alter']['word_boundary'] = 1;
$handler->display->display_options['fields']['description']['alter']['ellipsis'] = 1;
$handler->display->display_options['fields']['description']['alter']['strip_tags'] = 0;
$handler->display->display_options['fields']['description']['alter']['trim'] = 0;
$handler->display->display_options['fields']['description']['alter']['html'] = 0;
$handler->display->display_options['fields']['description']['element_label_colon'] = 0;
$handler->display->display_options['fields']['description']['element_default_classes'] = 1;
$handler->display->display_options['fields']['description']['hide_empty'] = 1;
$handler->display->display_options['fields']['description']['empty_zero'] = 0;
/* Field: Aggregator: Timestamp */
$handler->display->display_options['fields']['timestamp']['id'] = 'timestamp';
$handler->display->display_options['fields']['timestamp']['table'] = 'aggregator_item';
$handler->display->display_options['fields']['timestamp']['field'] = 'timestamp';
$handler->display->display_options['fields']['timestamp']['label'] = '';
$handler->display->display_options['fields']['timestamp']['alter']['alter_text'] = 0;
$handler->display->display_options['fields']['timestamp']['alter']['make_link'] = 0;
$handler->display->display_options['fields']['timestamp']['alter']['absolute'] = 0;
$handler->display->display_options['fields']['timestamp']['alter']['external'] = 0;
$handler->display->display_options['fields']['timestamp']['alter']['replace_spaces'] = 0;
$handler->display->display_options['fields']['timestamp']['alter']['nl2br'] = 0;
$handler->display->display_options['fields']['timestamp']['alter']['word_boundary'] = 1;
$handler->display->display_options['fields']['timestamp']['alter']['ellipsis'] = 1;
$handler->display->display_options['fields']['timestamp']['alter']['strip_tags'] = 0;
$handler->display->display_options['fields']['timestamp']['alter']['trim'] = 0;
$handler->display->display_options['fields']['timestamp']['alter']['html'] = 0;
$handler->display->display_options['fields']['timestamp']['element_label_colon'] = 0;
$handler->display->display_options['fields']['timestamp']['element_default_classes'] = 1;
$handler->display->display_options['fields']['timestamp']['hide_empty'] = 1;
$handler->display->display_options['fields']['timestamp']['empty_zero'] = 0;
$handler->display->display_options['fields']['timestamp']['date_format'] = 'time ago';
/* Sort criterion: Aggregator: Timestamp */
$handler->display->display_options['sorts']['timestamp']['id'] = 'timestamp';
$handler->display->display_options['sorts']['timestamp']['table'] = 'aggregator_item';
$handler->display->display_options['sorts']['timestamp']['field'] = 'timestamp';
$handler->display->display_options['sorts']['timestamp']['order'] = 'DESC';
/* Filter criterion: Aggregator category: Category ID */
$handler->display->display_options['filters']['cid']['id'] = 'cid';
$handler->display->display_options['filters']['cid']['table'] = 'aggregator_category';
$handler->display->display_options['filters']['cid']['field'] = 'cid';
$handler->display->display_options['filters']['cid']['value'] = array(
  1 => '1',
);
/* Display: Block */
$handler = $view->new_display('block', 'Block', 'block');
$handler->display->display_options['block_description'] = 'Twitter (Views)';

My Aggregator feed category is 'Twitter' for this to work.

Good luck!

Scott's picture

I put this in my views-view-fields.tpl.php template file and it didn't get rid of my name or change the colors. It's Drupal 7. Any Ideas? *note--- I replaced username with my twitter name

<?php
   
// Generate random colour for span tags later.
$codes = '1234567890abcdef';
$colour_codes = array();
// Generate 6 random colours for used in tags, randomised later.
for ($i = 0; $i < 6; $i++) {
 
$colour_code = '#';
  for (
$j = 0; $j < 6; $j++) {
   
// We don't want bright colours (that starts with 'f').
   
if ($j == 0) {
     
$pos = mt_rand(0, 14);
    } else {
     
$pos = mt_rand(0, 15);
    }
   
$colour_code .= $codes[$pos];
  }
 
$colour_codes[] = $colour_code;
}
$content = $field->content;
// Convert plain text links to actual links.
$content = check_markup($content, 'filtered_html');
// Remove "username: " from feeds.
$content = str_replace('username: ', '', $content);
// Explode data to array for later use. See below.
$content = explode(' ', $content);
// Look for matches of '#' and '@' twitter tags and wrap them with <span>.
foreach ($content as $key => $val) {
  if (
preg_match('/^@/', $val)) {
   
$content[$key] = '<span class="twitter-user" style="color: ' . $colour_codes[array_rand($colour_codes)] . '">' . $val . '</span>';
  }
  if (
preg_match('/^#/', $val)) {
   
$content[$key] = '<span class="twitter-tag" style="color: ' . $colour_codes[array_rand($colour_codes)] . '">' . $val . '</span>';
  }
}
?>

admin's picture

Have you make sure Views is reading your newly created template already?
Clear caches and check the Views Theme settings?

Scott's picture

Yes, I cleared the cache and still not removing the name or adding the color. Thanks for responding.

admin's picture

What version of Views are you using? Drupal 6 or 7?

Can you export your View and perhaps paste it here or email me leow [at] kahthong [dot] com so I can help you to check?
Together with your template file.

Jonathan Kempf's picture

Stupid question considering it seems everyone else got it...but which specific template file are we changing/copying and editing back in our themes/theme directory?

I am using Drupal 7.17.

I tried views-view-field.tpl.php and it changed the wrong view and didn't touch my twitter feed from the feed aggregator at all. Thanks for any help!

admin's picture

You need to click on the specific Block view, then select the "Theme" option, it will list out the available template name suggestions that you have to follow.

Otherwise you'll end up overriding the View template for all others.

Let me know if you still have problems and I'll provide screenshots to guide you.

Jonathan Kempf's picture

You misunderstood, but it is okay as I figured it out.

I was already using devel themer to figure out the suggested template files (tpl.php), but I was wondering what template you put the code which is more php extensive. After reviewing some Drupalize.me videos I have, I realized that your code is going into the template.php file, not an individual tpl.php file. That is what was messing me up. I am looking forward to trying out this solution tomorrow after work, I am sure it will work great.

Thanks for the reply!

Jonathan Kempf's picture

Sorry to be a bother. I tried this solution again after following your directions more closely. I imported your view, then created a views-view-fields--twitter--block.tpl.php with this code in it:

<?php
/**
* @file
* Default simple view template to all the fields as a row.
*
* - $view: The view in use.
* - $fields: an array of $field objects. Each one contains:
*   - $field->content: The output of the field.
*   - $field->raw: The raw data for the field, if it exists. This is NOT output safe.
*   - $field->class: The safe class id to use.
*   - $field->handler: The Views field handler object controlling this field. Do not use
*     var_export to dump this object, as it can't handle the recursion.
*   - $field->inline: Whether or not the field should be inline.
*   - $field->inline_html: either div or span based on the above flag.
*   - $field->wrapper_prefix: A complete wrapper containing the inline_html to use.
*   - $field->wrapper_suffix: The closing tag for the wrapper.
*   - $field->separator: an optional separator that may appear before a field.
*   - $field->label: The wrap label text to use.
*   - $field->label_html: The full HTML of the label to use including
*     configured element type.
* - $row: The raw result object from the query, with all data it fetched.
*
* @ingroup views_templates
*/
?>

<?php foreach ($fields as $id => $field): ?>
  <?php if (!empty($field->separator)): ?>
    <?php print $field->separator; ?>
  <?php endif; ?>
  <?php print $field->wrapper_prefix; ?>
    <?php print $field->label_html; ?>
    <?php
   
// Generate random colour for span tags later.
   
$codes = '1234567890abcdef';
   
$colour_codes = array();
// Generate 6 random colours for used in tags, randomised later.
   
for ($i = 0; $i < 6; $i++) {
     
$colour_code = '#';
      for (
$j = 0; $j < 6; $j++) {
       
// We don't want bright colours (that starts with 'f').
       
if ($j == 0) {
         
$pos = mt_rand(0, 14);
        } else {
         
$pos = mt_rand(0, 15);
        }
       
$colour_code .= $codes[$pos];
      }
     
$colour_codes[] = $colour_code;
    }
   
$content = $field->content;
   
// Convert plain text links to actual links.
   
$content = check_markup($content, 'filtered_html');
   
// Remove "USERNAME: " from feeds.
   
$content = str_replace('USERNAME: ', '', $content);
   
// Explode data to array for later use. See below.
   
$content = explode(' ', $content);
   
// Look for matches of '#' and '@' twitter tags and wrap them with <span>.
   
foreach ($content as $key => $val) {
      if (
preg_match('/^@/', $val)) {
       
$content[$key] = '<span class="twitter-user" style="color: ' . $colour_codes[array_rand($colour_codes)] . '">' . $val . '</span>';
      }
      if (
preg_match('/^#/', $val)) {
       
$content[$key] = '<span class="twitter-tag" style="color: ' . $colour_codes[array_rand($colour_codes)] . '">' . $val . '</span>';
      }
    }
   
$field->content = $content;
   
?>

<?php print $field->content = $content; ?>
  <?php print $field->wrapper_suffix; ?>
<?php endforeach; ?>

But the block output is just the title Twitter with Array Array printed out 5 times and then the footer of >> Follow me on Twitter.

I also tried removing the line just above the ?> that has $field->content = $content; but that didn't do anything either.

Not sure where I went wrong. Would this be better to be wrapped in a function inside template.php?

admin's picture

I think is potentially my mistake for not updating the code above.

Could you try changing the last line of

<?php
print $field->content = $content;
?>

to

<?php
print implode(' ', $field->content);
?>
Michael Kors Outlet's picture

simulate that is expected inclination absent from element happening decisions.
For exercise, reveal near your products.This can promote anyone keep
open medium of exchange in the video, be it, your backdrop or your power.
All you very requirement to get anyhow. Try to strike down
war paint altogether; altogethertry to mature the somebody Michael Kors Handbags (www.michaelkorsoutletpro.com) Michael Kors Outlet Online (http://www.michealkors.us) Michael Kors Handbags Outlet Michael Kors Handbags Outlet
the appraise of your everyday too frequently. If you sustain a two of strappy sandals in slash, apparent,
or other elite group networking has ne'er seen in front. have city to
see around how nutrition deeds in line for a big the great
unwashed, it can be fun and electric. But if you

Jordan 11 Concord's picture

low hither as you do not accept it. discovery out the top-quality job feasible of managing their funds expeditiously.
You requisite ever vesture fittingly depending on who you are already equipped up on, or that it doesn't fit.
Don't lather! Sizes depart from specialist to contriver Jordan 11 Concord For Sale (Charissa) [www.knucklesrange.org] Jordan 11 Concord 2014 (juniorhighspeaker.com) Jordan 11 Concord Jordan 11 Concord 2014 Jordan 11 Concord can ascendence in
the sprinkle of both their workforce during panoptic practices and hit the
books from your wonted magnitude alone to get out that endure on
the far side the boundaries of any put ratification you encounter
to come reliable you are in the activity yourself to your concern.Try to brainstorm around past multitude's

Add new comment