Creating Custom Beans in Drupal, Part 1
by Aaron Froehlich
*Feel free to browse the code from this tutorial in my sandbox repository at Drupal.org.
This tutorial is a follow-up to a recent article on Minimalist Drupal Development, where I made the case for judicious module selection as a strategy for keeping Drupal sites more performant and enjoyable to code. In this tutorial, I'll demonstrate how to create a Twitter timeline block using the Bean API. Ironically, a similar module appeared recently, called "Twitter Timeline" and released by Tom Kirkpatrick. The main difference here is that this solution relies on Drupal's cache and our own custom output rather than Twitter's widget system.
Start by finding a Drupal installation on your local system that we can use for this tutorial. On my system, I set up a fresh installation of Drupal 7.21. From the command line, head to the root of the project and create the folders we'll need for our custom module with mkdir -p sites/all/modules/custom/bean_tweets/plugins/bean
. In the root of of our custom module, let's start by creating a file called bean_tweets.info touch sites/all/modules/custom/bean_tweets/bean_tweets.info
, with the following lines:
From there, we'll create the module file touch sites/all/modules/custom/bean_tweets/bean_tweets.module
, where we can set up the basics of our custom bean:
At this point, our module is doing two things: 1) Declaring the API version our module implements, and 2) declaring our bean type. I had a little trouble in this section with some of the other online tutorials I followed when creating my first custom bean, so notice in particular the handler key and values, which include a class name (TweetBlockBean), and the path to the class we'll create now, with touch sites/all/modules/custom/bean_tweets/plugins/bean/bean_tweets.tweet_block.inc
, where we will add the stub code we'll need for that file:
This plugin class will do three things:
1) It's going to create the form for configuring our Bean.
2) It's going to allow us to set the default values of the form elements.
3) It's going to implement the view for the bean and add it to the render array.
Let's start with the form:
As you can see, we're adding a form element that the will allow the admin to configure a custom block instance. One of the things that makes this great is that we can create multiple tweet blocks for different twitter handles. Next, we need to make sure that some default values get populated:
This should be pretty self-explanatory, but notice that we're setting the handle to a blank string, and the number_of_tweets to 5. With our form elements in place, let's go ahead and set up the view for each block:
Notice we're hitting the json feed of the API, which returns a lot more data than we need. For the purposes of this tutorial, we're simply using the 'created_at' and 'text' nodes for our block of tweets. We'll return to the view in another tutorial and work through some refactoring that will integrate our work here with Drupal theming.
If we stop and take a look at our custom bean at this point, it looks pretty good. However, there's one clear limitation that we need to consider, which is Twitter's usage limits. With the code as it now stands, a heavily-trafficked site that implements our custom module could hit Twitter's rate limit of 100 API calls / hour. Additionally, our module is going to require that each page load on the site that includes one of our tweet blocks has to complete our API call during the page load, which is going to affect the end user's experience. Let's add some caching strategies:
As you can see, caching is accomplished in three parts: First, we add the logic to the view that checks to see if a cache value exists, and makes the API call if not and caches those results. Secondly, we want the user to be able to control how long the results get cached for, and so we add that textfield to the form, and establish a default value of 30 minutes. Finally, we added a submit handler to the form, so that the cache for the results gets cleared each time the block is updated. Next, we add that cache clearing mechanism to the module:
Our final step is to add our bean plugin file to our module info page:
After enabling our module with drush en bean_tweets -y
, which, as your drush output reveals, also downloads and/or enables the required modules (bean, entity, ctools), we're ready to clear cache with drush cc all
, and check out our new tweet block.
We should now see a new menu item on the admin/content page, called "Add block", where we can create our tweet block. After creating a block, it should appear on your block listing page, where you can add it to a region, or follow your chosen block placement strategy.
Thanks for following this tutorial. If you'd like to download or play with the code, there is a sandbox repository at Drupal.org. In part two, we'll dig into OAuth and upgrade to Twitter's 1.1 API.