Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough
Jan 21 2013
Jan 21

In honor of Module Monday's post-holiday return, we're taking a look at a problem that plagues many sites: dead links. If you maintain content that contains links to other sites, it's inevitable that some of them will ultimately go bad. Domains expire, sites go down, articles are unpublished, blogs migrate to a new CMS and change their URL patterns... and eventually you're left with a dusting of broken URLs in your otherwise pristine content. That's where LinkChecker comes in. It's a module for Drupal 6 and 7 that scans your content for busted links, tells you what nodes need fixing, and -- optionally -- tidies up the ones it can fix automatically.

Screenshot of administration screen

LinkChecker runs at cron time on your Drupal site, churning its way through a bite-size number of nodes each time and scanning them for URLs. It pings those URLs, makes sure a working web page is still there, and moves on. If not, it logs the specific HTTP error for later reference and moves on. It's handy, but the devil is always in the details -- and LinkChecker is designed to handle all of them with aplomb. Do you need to white-list certain content types to ensure they aren't scanned? No problem. Need to make sure that dummy URLs like "example.com" don't get checked and generate false positives? It handles that, too. Need to hunt for urls contained in dedicated CCK or FieldAPI Link fields, in addition to text fields and node bodies? No problem. Want to check image links that reside on remote servers, or check URLs that are generated by Drupal input filters even though they don't appear in the "raw" text of the node? LinkChecker allows a site administrator to toggle all of those options and more.

The module can correct kinds of errors automatically (301 redirects, for example) but it's up to the site's administrator to check the report that it generates for news about broken links. There, each node with busted links can be reviewed and edited.

Screenshot of resulting change to site

LinkChecker is a tremendously useful tool, and its smorgasbord of configuration options means that it can deal with lots of oddball edge cases. One missing option that would still be welcome? An easy way to export the "busted links" report to a text file for review. For extremely large sites, dedicated third-party web crawlers with link checking functions may be a more robust solution, but for Drupal admins who need a hand keeping their sites tidy, it's a lifesaver.

Dec 31 2012
Dec 31

Make 2013 safer with a backup plan for your site

Ah, New Years Eve. It's the time for parties, reminiscing, and the old tradition of New Years resolutions. We promise ourselves we'll exercise, read that important book, donate to charity, or -- depending on the number of web sites we're responsible for -- vow that this is the year to set up a backup plan. Few things, after all, are more terrifying than the realization that a server hiccup has wiped out a web site, or a hasty change deployed to the live site has nuked important content. Fortunately, there's a module that can help. Backup and Migrate offers site builders a host of options for manually and automatically backing up their sites' databases -- and integrates with third-party backup services, to boot!

Screenshot of Backup and Migrate settings

Backup and Migrate offers a number of options for preserving your Drupal site's database, but all of them revolve around three important choices. You can choose to backup just a select group of database tables, or the whole kit and kaboodle -- useful for ditching the unwieldy cache and watchdog tables that Drupal can easily recreate. You can choose the destination for your backup -- drop it into a private directory on your server, download it directly to your computer if you're performing a manual backup, or send it to several supported third-party servers. And finally, you can run backups manually or schedule them to occur automatically.

In its simplest form, you can use the module to manually pull down a snapshot of a site's database for safe keeping, or to do local development with the latest and greatest production data. For real safety, though, you can tie it to services like Amazon S3 storage, or the new NodeSquirrel offsite backup service. Set up scheduled daily or weekly backups, tell it how long to keep existing backups around, and rest assured that regular snapshots of your site's critical data will be tucked away for safe keeping when you need them.

When disaster strikes, you can use the Backup and Migrate module to upload one of those database backups, and restore your site to the state it was in when the backup was made.

Screenshot of the Restore Backup screen

It's important to remember that Backup and Migrate won't solve all of your problems. It requires a third-party addon module (Backup and Migrate Files) to archive and restore the site's important file uploads directory, for example. In addition, the easy one-click backup and restore process can tempt developers to forgo safe deployment strategies for new features. Just because it's possible to download a database snapshot, do configuration work on your local computer, then re-upload the snapshot to the live server, doesn't mean it's a good idea.

That said, Backup and Migrate is an excellent tool that's proven its worth on countless sites. Its clean integration with third-party file storage services also means that it's a great transitional path towards a full-fledged backup strategy for business-critical data. If you aren't using it, check it out -- and enjoy the peace of mind that comes with keeping your site's data safe.

Dec 24 2012
Dec 24

Every week, Module Monday offers a quick peek at useful but lesser-known Drupal modules. Every week, that is, save Christmas, when we put on a Santa cap and pick a fun-and-useless novelty module to brighten the holidays. This year, it's the appropriately themed Christmas Snow module! It adds friendly flurries to any Drupal site for the holidays.

Screenshot of Christmas Snow configuration options

Surprisingly, Christmas Snow comes with a tricked-out configuration screen, allowing administrators to choose options like snow speed, wind direction, and the balance between smooth animation and increased system load as a visitor's browser animates all those flakes. The result? A blizzard!

Naturally, Christmas Snow isn't the sort of module you'd want to use year-round. (Even leaving it enabled for the holidays on a high traffic site is, well, a matter of taste.) But if you're looking for a holiday snow effect for your Drupal site, look no farther: this module does it in style. Merry Christmas, Drupallers!

Nov 26 2012
Nov 26

Media heavy Drupal sites feel the pain of bandwidth costs in a big way. Simply dropping a few large rotator images on your site's home page, for example, can bloat load times and inflate costs for network and CDN usage on high-traffic sites. Drupal 6's ImageCache module (now built into Drupal 7's Image module) can scale images down to the correct size automatically, but JPEG and PNG images still have a lot of space left to give: specialized utilities can crunch them down to save additional space without compromising quality. That's where the ImageAPI Optimize module comes in: it allows you to pipe all uploaded images through those optimizers automatically.

Screenshot of administration screen

Installing ImageAPI Optimize is easy on the Drupal side -- drop the module in place, turn it on, and head to the Image Settings configuration page. Normally, Drupal provides a simple 'quality selector' on that page to control the level of compression for scaled JPEGs. With this module installed, however, site builders can specify the specific compression and optimization utilities that should be used to crunch image files as much as possible.

Most of the supported utilities will need to be installed on your web server before they can be used, but if you don't have server access or just want to try things out, you can point the module to Yahoo's hosted Smush.it service. For designers who hand-tweak every image in Photoshop, or make manual use of "Export to Web" compression features in their image editors, the utilities supported by ImageAPI Optimize may not make a huge difference. But when users or non-designers are allowed to post images as part of Drupal content, ImageAPI Optimize can help ensure that you're saving all the space (and bandwidth) you can.

Nov 05 2012
Nov 05

How to Tidy URLs and Relative Links When Moving From Dev to Go-Live (for Drupal 6 and 7)

Few things are as annoying as building something that works perfectly when you create it, but fails when you take it out of the lab. That's how site owners can often feel when content editors create piles and piles of Drupal nodes full of relative URLs in images and links. They look fine on the site, but if the content is syndicated via RSS or Atom, sent out in an email, or otherwise repurposed in another location, the links break. Even worse, hand-made links and images entered while the site is under development can easily point to the outdated "beta" URL. Who can save the day? Pathologic module, that's who.

Pathologic module's configuration options

Pathologic is an input filter -- to install it, you drop the module into your Drupal site and add it to one of your text formats -- Full HTML and Filtered HTML, for example. Whenever content is posted in a format configured to use Pathologic, it will scan the content for URLs and tidy them up. Relative URLs like /node/1 get turned into absolute ones like http://example.com/node/1, URLs pointing to alternative versions of your site like dev.example.com are replaced with your public URL, and so on.

Pathologic can also standardize the protocol of links inside your site's content. If users edit content over a secure connection, for example, it's easy to mix links using the http:// and https:// protocols -- something that can lead to annoying warnings on some users' machines. For developers with exacting URL-correcting needs, it also supports custom URL modification hooks. Using those hooks, your site's custom fixes (replacing MP3 links with a URL on a different server, for example) can piggyback on Pathologic's configuration and logic.

Pathologic is an efficient workhorse of a module that solves an annoying problem efficiently. If you've run into problems with relative links and staging-server URLs breaking links and images on your RSS feeds, you owe it to yourself to check it out!

Oct 23 2012
Oct 23

A case study in re-platforming latingrammy.com


The previous version of the site was built on Ruby on Rails in a custom content management system that allowed administrators of the site to have content types, categories, and even translations. This was all stored in a MySQL database with a simple schema that allowed for a pretty easy migration into Drupal.

The task was to re-create the entire site within Drupal, keeping the exact same content types, content, and existing design with the exception of a new homepage, new header and new footer. The new homepage design is based off of the current Grammy.com's homepage design.

Previous Homepage:

Newest Homepage:

The Recording Academy wanted to re-platform this on Drupal for a couple of reasons. The first is that since Grammy.com is on Drupal 6 and will be upgraded to Drupal 7 before the next annual awards show, we could leverage some of the work in building the Latin Grammys website with Drupal 7 for the upgrade of Grammy.com itself. The second reason was to bring the site more inline with Grammy.com in terms of capabilities in content editing, advertising, and future enhancements to the site could be leveraged from any improvements that end up being made on Grammy.com.


For the migration work on this project, we decided to create a custom drush command that could run the various migration scripts. The scripts are split out by content type: each script migrating the pertinent information for a particular content type. They are comprised of a simple function that runs bootstrapped Drupal code to take data from the old Ruby database and transform it for the new Drupal database.

You can find the code for this custom drush command, $ drush lmi in this gist.

We then have one simple bash script that runs drush commands in succession, like so:

# Clean install using our installation profile written with profiler.
drush site-install lagra -y
drush upwd admin --password="admin"
drush fra --force -y
drush dis overlay -y
drush cc all

# Migrate taxonomy terms.
drush lmi tag
drush lmi genre
drush lmi award

# Migrate content.
drush lmi event
drush lmi nominee
drush lmi page
drush lmi photo
drush lmi podcast
drush lmi press_release
drush lmi sponsor
drush lmi video import

You may also notice that within that bash script, we are installing Drupal from scratch with a custom install profile called 'lagra'. This installation profile is using Profiler and does some simple enabling of core modules, contrib modules, custom features, and sets a few initial variables within the variables table. If you haven't looked into using Profiler on your projects, you should. It allows you to do some pretty complex operations with very simple syntax right in your profile's .info file.

You can find the code for this custom install profile in this gist.

What this all leads to is a relatively simple and quite an efficient way to completely reinstall the entire project from scratch at any given point. All of the features of the site are in custom Features modules, and the migration scripts run automatically, so a fresh install of the project is as easy as running $ ./docroot/scripts/reset.sh at any given time. We found this led to a very rewarding workflow during the entire duration of the project.


Another huge requirement for the site (in fact, one we underestimated) was the use of three different languages on the site: English, Spanish, and Portuguese. For this we had to add a whole slew of i18n_* modules. Here's the list:

  • Internationalization (i18n)
  • Block languages (i18n_block)
  • Menu translation (i18n_menu)
  • Multilingual content (i18n_node)
  • Path translation (i18n_path)
  • String translation (i18n_string)
  • Taxonomy translation (i18n_taxonomy)
  • Translation sets (i18n_translation)
  • Variable translation (i18n_variable)
  • Views translation (i18nviews)
  • I18n page views (i18n_page_views)


The old Ruby system had a very competent system for managing translations of content. However, not all content in the system was translated, and so there were some challenges in making sure that we could switch to a different language and not have the page show up empty simply because the content was not translated for that particular views listing. The listing being empty was not ideal from a user's standpoint, nor from a content editor's standpoint. So we opted to do a little extra work in the migration scripts for the particular content types that did not have translations. We simply created the English version of the nodes, and at the same time used the same copy for the translations. This resulted in populated views for each language, and an ideal way for content editors to browse the listings and quickly know what content needed to be translated, hit an edit button, and then translate.

Another challenge we didn't account for was all of the strings that are not translated automatically. The String translation module was easy enough to use for most cases, but for the times we found it lacking, we ended up using the String Overrides module to fill in the gaps.

We also found that keeping string translations in code was problematic. We opted for using the $conf array like so:

global $conf;
$conf['locale_custom_strings_es'][''] = array(
"You must be logged in to access this page." => "Debes estar registrado para acceder a esta página.",

However, this also became an issue once we decided to start using the String Overrides module because the $conf array would simply override any translations we would put in the String Overrides UI. So, we opted to use this $conf array method to get the values into the database initially (hitting save in the String Overrides UI) and then just remove the $conf array. Then, we could use the UI to translate the few strings that remained.

This is still something we haven't solved, so if you have any suggestions on easily keeping string translations in code (à la Features), we would love to know about it in the comments!


The following were involved in this project at various stages and in various roles:

In order of code contributions.


Brock Boland: Developer at Lullabot


Jerad Bitner: Senior Developer & Technical Project Organizer at Lullabot


David Burns: Senior Developer at Lullabot


Angus Mak: Developer at Lullabot


Ben Chavet: Systems Administrator at Lullabot


Bao Truong: Software/Web Developer at The Recording Academy

Oct 15 2012
Oct 15

Almost a year ago, Module Monday featured the Views Datasource module, a tool for exposing custom XML and JSON feeds from a Drupal site. It's a great tool, but what if you need something a bit more... human-readable? A .doc file, or a spreadsheet for example? That's where the similarly-named but differently-focused Views Data Export module comes in.

Screenshot of administration screen

Views Data Export provides a custom View display type optimized for producing downloadable files in a variety of formats. Need a Microsoft Excel file with a list of the latest 100 posts on your site? Looking for a Microsoft Word .doc file that collects the text of the site's top-rated articles? No problem. The module supports XLS, DOC, TXT, CVS, and XML exports with format-appropriate configure options for each one. In addition, it uses Drupal's batch processing system when it's asked to generate extremely large export files, rather than timing out or giving out-of-memory errors.

Screenshot of resulting change to site

Whether you're putting together reports, giving users an easy way to download product data sheets, or conducting a quick, ad-hoc audit of your site's content, Views Data Export is a handy tool to have around. Its batch processing support makes it more reliable on large sites, and its support for a variety of "day to day" file formats means you'll spend less time juggling your data and more time making use of it.

Oct 09 2012
Oct 09

In the first episode of Insert Content Here, Jeff Robbins and I chatted about the temptation and the danger of the "Dreamweaver Field" content model. When content types are just wrappers around giant chunks of hand-formatted HTML, editors have lots of flexibility but it's all but impossible to repurpose the hard-coded content for new designs and publishing channels.

In presentations, articles, and her upcoming book, Content Strategy for Mobile, Karen McGrane describes the problem as a war of "Blobs" versus "Chunks." The challenge is figuring out how to decompose a site full of inflexible HTML blobs into discrete, bite-sized fields. There's no magic bullet (a model that works for one project can fail miserably for another), but over the past several years we've accumulated a few useful rules of thumb for "deblobbing" a site's content.

The Basics

Don't skimp on the content inventory and auditing process. Figure out what's there, what's going to be tossed, and what you want to have on the site. This is step zero, really: the modeling process is infinitely harder if you're dragging around piles of HTML that don't match what your're trying to build.

Clump similar content. If your existing site doesn't have discrete content types, figuring out which pages are similar to each other is the next stage. Product reviews, staff bios, press releases, blog entries, portfolio slideshows… You know the drill. Remember to look for pages and content types that are really composites of other, smaller units of content. Often, some of the most complex pages and content types can be implemented as rule-based or curated collections of smaller, more management content types.

Look for common "chunk" types. Once you've grouped your blobby content types into similar pools, zoom in and look for patterns that are unique to each content type. These are are potential candidates for dedicated fields. Some of the common field types we encounter include:

  • Links to related content
  • Links to downloadable files and embedded media that occur at consistent locations
  • Publication or event dates
  • Pull quotes, hand-written taglines, author bios, and summaries
  • Business and event addresses
  • Geographical locations and maps
  • Lists of information like features or rules and requirements
  • Ratings, prices, and product codes

Most CMS's support multi-value fields that can be used to model repeating elements like feature lists or multiple file attachments. Be sure to note which elements occur once, and which ones repeat.

Rinse and Repeat. Once you've broken things into multiple content types and identified the discrete fields on each one, look for overlaps. Are there several content types that share the same list of fields? Consolidating them into a single type might simplify things. Is there one "Godzilla" content type with dozens and dozens fields? It might really be several types that should be teased apart. The first pass of a content model is a lot like the first draft of an essay: there are always rough edges and awkward parts that need work.

The Tricky Bits

After identifying all of that easy stuff, large and complex sites usually have quite a few ugly blobs that still need to be broken down.

Identify composite content. Sometimes, elements of one content type need to be broken out into their own sub-content-types, with simple parent-child relationships connecting them. Galleries that contain multiple photos, albums that contain multiple songs, and curated pages that include teasers for other content are common examples. If several content types in your model contain the same cluster of fields (like photo, caption, byline, and link, consider splitting out the cluster into a its own dedicated content type. Treating those scenerios as relationships between discrete elements can often simplify complex models.

Look for common formatting complexities. If you have wireframes or existing pages, look for complex visual formatting around certain elements, in particular the stuff that requires lots of hand-written HTML to implement in a "content blob." Comparison tables are a common offender here. Breaking these out into dedicated fields whenever possible can help prevent massive pain when a piece of content needs to be displayed differently in new channels.

Watch for design elements that change based on context. If you're building a responsive or adaptive site, or have access to designs for mobile apps or other output channels, keep an eye out for elements that appear differently or conditionally based on breakpoints, target device, and so on. It seems obvious, but controlling small elements is infinitely easier when they're broken out as discrete fields.

Plan for searching and filtering. Try to identify as many different filtered lists of content as possible. Faceted search screens, topical landing pages, author-based blogs, product lists, and so on can't be built efficiently without the right data. If the lists and search indexes that you need don't correspond to fields you've already broken out, remember to add additional ones for the required metadata.

Isolate the crazy. Inevitably, complex designs end up requiring "helper" content that doesn't seem to fit the well-understood content types the site's stakeholders imagine. Slides for promotional rotators, free-floating promotional microcontent for landing pages… These tend to be highly variable and often need the kind of raw-HTML flexibility that we're trying to avoid. Isolating them in their own content types and living with the cordoned-off craziness can help simplify models with overloaded, field-heavy primary types.

Recognize when markup is good enough. Despite all the talk about the dangers of blobs, it is possible to go too far. Replacing every HTML div and span with a dedicated field simply to avoid raw markup is overkill, and can easily result in 'Edit Screens of Doom.' Modern WYSIWYG editors generally support plug-in systems, and developing a button to "insert caption here" or "style paragraph as warning" can be a simpler solution. This is where I repeat the warning: There's no perfect content model, only the one that works for your project.

Test the Model

The long-term impact of a bad model on a site's maintainability can be frustrating, but it's also impossible to predict every future application the content will be used for. Iteratively testing the model against real-world content and potential applications is critical.

Put real content into the model. It seems obvious, but it's easy to go down the structural rabbit hole and forget the existing pool of content. Circle around frequently and ask, "How does the content we have in hand fit into these content types and fields?" Look for odd mismatches, required fields that the existing content will leave unpopulated, and so on. Sometimes, the design and the model have to change for practical reasons. Other times, clients or your team will have to update the content to close the gap.

Plan for three channels. When building a model (or a software API), it's easy to imagine you're creating a reusable system while unintentionally baking in assumptions that make real reuse difficult. If you need content that will adapt to reuse in new channels, be sure that you keep at least three in mind -- think of them as user personas for the model. Desktop web, small-display devices, and rich HTML newsletters are common answers for some businesses. Even if you're only building one of them at first, proposed approaches can be compared against them to ensure you aren't painting yourself into any corners.

Social sharing is a publishing channel, too. Twitter and Facebook can automatically embed headlines, summaries, and preview images when users paste one of your site's links -- if you provide the metadata that they're looking for. If your model doens't account for those, it will be much tougher.

Let real users work with it. If you're using a web framework that allows rapid creation of a content model before the full site is finalized, or you can produce wireframes of some sample content input and editing screens, get user feedback sooner rather than later. The people who spend their time creating and maintaining the content can often spot problems and inconsistencies that would otherwise remain undiscovered until launch.

No Rules, Just Lessons

None of above ideas are hard-and-fast rules, obviously. At Lullabot, we've spent years building out complex sites (and the underlying content models) for media publishers, government agencies, corporate intranets, ecommerce sites, and more. And yet, every new client comes with surprises and challenges.

In the coming months, I'll be digging deeper into each of these ideas with follow-up articles and interviews on Insert Content Here. In the meantime, what useful heuristics do you use when breaking down ugly "content blobs" into reusable chunks? Feel free to chime in with comments!

Sep 27 2012
Sep 27

Lullabot's Drupal training site turns 2

It's been almost 2 years since we launched Drupalize.Me and I'd like to take a moment to appreciate some of the site's recent accomplishments.

Over 600 Videos

A few weeks ago, Drupalize.Me product manager Addison Berry announced the 600th video posted to Drupalize.Me! Members now get access to over 233 hours of content on an immense range of Drupal-oriented topics from simple content creation to site building tricks and database server performance optimization. Drupalize.Me's most popular videos cover coding for and using Views, using the Calendar and Date modules, configuring WYSIWYG editors, Display Suite, Organic Groups, Drupal 7 module development, and more. The Drupalize.Me team has been really amazing – posting new videos every week and paying close attention to member requests for new topics.

Over 2,000 Subscribers

Word about Drupalize.Me has spread and I often see people on Twitter telling one another that for them, Drupalize.Me has become the way to learn and keep up with Drupal techniques. Drupalize.Me has iPhone/iPad, Android, and Roku apps so members can watch the videos on their mobile devices or televisions. Drupalize.Me has also partnered with Acquia to offer discounted memberships to Acquia Network subscribers.

As word has been getting around about Drupalize.Me, subscriber numbers have been growing and recently crossed 2,000 simultaneous subscribers. We're reaching more people on a monthly basis than most large-scale Drupal events. We couldn't be more excited about the response!

Drupalize.Me now has a staff of 3 full-time people creating videos, maintaining the site, adding features and handling customer support. This team is augmented by others at Lullabot who step in to help with expert video training, development, design and support. Drupalize.Me now represents more than 15% of Lullabot's budget and has become a great outlet for the Lullabot team to share the knowledge that we've gained building the high-profile websites that represent the majority of our work.

New Features

The Drupalize.Me team has been listening closely to subscriber feature requests and we've gotten lots of new features over the past 2 years. They've arranged videos into "series" collections and allow users to watch them consecutively. They've also added curated "guides" collecting videos into linear curriculum for different types of members. They've also greatly improved the user dashboard pages allowing users to manage their queue as well as see the listing of recently watched videos and even displaying a line graph so members can see their progress within the videos they've watched. The team also added the ability to store pause points and allow users to resume from exactly where they left off - even if they're resuming on a different device such as their phone or connected television.

And speaking of connected televisions, we've got apps! We've got an iOS app for your iPhone/iTouch/iPad which can AirPlay to your AppleTV. We've also got an Android app and an app for the Roku Streaming Player box. You can pick up a Roku box for as little as $50, hook it up to your television, and watch all of the Drupalize.Me videos from your couch. It's a great way to learn.

Group Memberships

Drupalize.Me also offers group memberships. If you want Drupal training for your entire group, department, company, or institution, we offer that too. Group accounts greatly reduce the price of individual accounts while still allowing each group member to manage their own video queue, resume videos, and see their own history. We offer both managed group plans and IP-range plans to allow access to all devices at a physical location such as a library or campus.

Subtitles, Transcripts & Translations

Perhaps the greatest new features at Drupalize.Me are the ability to offer subtitles, transcripts, and translations for the videos. We have many international subscribers who, while they speak and understand English, sometimes can't keep up with the rapid-fire technical information in the videos. They've been asking for English-language subtitles and transcripts so they can follow along better. We're proud to say that we've added this functionality as well as functionality to provide complete translations with subtitles in other languages! 60 of our recent videos as well as the complete Introduction to Drupal guide already have transcripts and subtitles. And all new videos published on Drupalize.Me in the future will have transcripts and subtitles.

We're currently looking for volunteers to do foreign language translation for Drupalize.Me. If you're a bi-lingual Drupalist and you'd like to help make bring these Drupal training videos to the world, please contact us!

Drupalize.Me & Videola

One of the Drupalize.Me team's biggest accomplishments is building the Drupalize.Me site itself. The team has built a great Drupal-based platform which manages both the permissions and delivery of adaptive bitrate streaming video; recurring subscription billing and administration; video content categorization, listing, and organization; mobile app and IPTV delivery with seamless pause-on-one-device-resume-on-another functionality; and now even multi-language subtitles and transcripts.

As we've been building Drupalize.Me, we've been funneling this work and knowledge into Videola, a platform to provide this functionality to others wanting to build subscription-based or IPTV-oriented video sites. In short, Videola is a framework for building sites like Drupalize.Me... or like Netflix, Hulu, or Amazon video-on-demand. Videola can do everything that Drupalize.Me can do and more. If you'd like to build a site like this, please contact us and we can talk to you about getting you set up with a Videola site of your own.


Addi and the rest of the Drupalize.Me team have been doing a lot of training at DrupalCons, DrupalCamps, and other events. They've been very involved in the Drupal Ladder project and have posted a series of free videos to help new Drupalers get involved with core development.

Drupalize.Me recently started its own podcast (which picks up where the long-running Lullabot Drupal Podcast left off). Every other Friday, the Drupalize.Me team is posting a new podcast with interviews and discussions to help listeners keep up with the ever-changing world of Drupal. The team is also constantly upgrading and improving the site and they've got lots of great feature ideas for the future.

I couldn't be more proud of the work that's been done by Addi Berry, Joe Shindelar, Kyle Hofmeyer, and everyone who's helped with Drupalize.Me over the past 2 years. The site just keeps getting better and better. At this rate, I fully expect that 2 years from now I'll be bragging about their Drupal training neural implants and interstellar 3D streaming. But for now, I'm really happy with where we are – doing great, having fun, and sharing knowledge with people, empowering them to do great things.

Sep 03 2012
Sep 03

There comes a time in every Drupal site builder's life when a content type must redirect to another page. Perhaps your site contains a collection of links, and you'd like visitors to see the destination site itself rather than the node that describes it. Perhaps your site features small chunks of promotional content that point to other nodes, and shouldn't be treated as primary content themselves. Wouldn't it be handy to redirect to the destination content automatically when the promotional node is visited? It certainly would -- and that's precisely what the Field Redirection module delivers.

The heart of the module is a well-implemented field formatter. If you have a content type that uses a Link field, a Node or User reference field, or an Entity Reference field, you can assign it the Field Redirection formatter. When the node (or any other entity with fields using this module) is viewed, Field Redirection doesn't render the field as HTML -- instead, it redirects the user's browser to the referenced user profile page, node page, link URL, and so on.

Screenshot of Field Redirection configuration screen

Because Field Redirection sidesteps the normal FieldAPI behavior of 'Building HTML for Display,' there are important caveats. The formatter should only be used on the Full Content build mode for an entity. If it's used for teasers, RSS feeds, Search indexing, Views listings, or other modes where it could be unintentionally triggered, your site will be redirecting itself to new URLs instead of executing important code. That warning aside, the module is an elegant and easily customizable solution to a common problem. If you're building lightweight "linking" content types that point at other elements or other URLs, Field Redirection can make life quite a bit easier.

Aug 27 2012
Aug 27

One of the basic building blocks of a functioning publishing tool is the ability to view, edit, and preview content before it's published. In older versions of Drupal, that was an all-or-nothing affair: either you gave people the dangerously overpowered "Administer Content" permission, or you downloaded a comprehensive access control module and started building a custom permissions system of your own. In Drupal 7, it improved: roles can be given permission to view their own unpublished content, or given the ability to bypass all content access control, but it's still a bit clunky for a lot of very common use cases. Thankfully, there's the aptly-named View Unpublished module. It brings juuuuust enough control without requiring a complex permission matrix.

Screenshot of administration screen

Once you've installed View Unpublished, a set of new permissions becomes available. You can grant individual roles the ability to view other users' unpublished content on a per-content-type basis. With that one addition, it becomes much easier to build simple editorial dashboards that give editors or contributors limited access to other writers' work before publishing, or for all the members of a team to see what the site will look like once content goes live.

Normally, we'd include a screenshot of the module 'in action,' but the simplicity of the tool makes that a bit tough. When View Unpublished is working, most users don't see anything at all! There are a few limitations to the module's streamlined approach, of course. Permission to publish and unpublish content is still handled by other tools, and it's up to you or another site builder to construct a functional "dashboard" for unpublished content if it isn't already listed on the front page or another easy-to-find location. For quick and simple access permissions on limited publishing workflows, however, View Unpublished is a great tool.

Aug 20 2012
Aug 20

Managing user roles in Drupal is easy -- at least, technically easy. It's a bit trickier if you have a large user base and need to manage a steady stream of people requesting access to specific privileges, new roles, or additional responsibilities. If you're in that situation, get ready for some quality time with your email client, and set up a regular appointment with Drupal's User Management screen. Fortunately, the Apply For Role module can simplify the process.

Screenshot of Apply for Role management screen

With Apply For Role, users can visit a new tab on their user account page and request access to a new role on the site. The request is queued up for an administrator, who can review, approve, or deny requests from a central management page. Requests can also be deleted -- allowing the original user to re-submit their request later -- or denied, ensuring that they can't send in more requests for the same role.

Screenshot of Apply for Role configuration form

The module allows site builders to set up which roles can be applied for (to prevent users from getting a glimpse at roles they should never have access to), prevent or allow multiple simultaneous role requests, and so on. For site builders who want extra control, the module also provides full Views integration, as well as integration with Trigger module. You can easily build a custom administration screen to manage role applications, complete with notification emails.

There are a few noticeable gaps in Apply For Role's functionality. The application form that users fill out is spartan and lacks any explanatory text; giving administrators a way to add more help text to that page would go a long way. In addition, it would be great to customize the names of the roles that are presented to applicants. Most sites' roles are never shown to normal users, so they're often named for brevity rather than clarity. Both of those oversights can be remedied with some minor hook_form_alter() work in a custom module, but it would be great to see them integrated. Even without those wish-list items, Apply For Role is a slick solution to the problem of processing large numbers of permission-change requests. If your site's user management workflow is a good match, you should definitely check it out.

Aug 14 2012
Aug 14

Drupal's standard node options cover quite a bit of ground: content editors can control the publication date, author name, revision status, revision log message, "sticky" flag, published status, and front page promotion status of every piece of content! Of course, there's no way to give content editors access to just one of those options. If you want an editor to control the "published" flag but none of the others, you're out of luck. It's all or nothing, and the resulting array of checkboxes and form elements can easily overwhelm users who are new to Drupal. Unless, of course, you install the Override Node Options module...

Screenshot of administration screen

Setting up the module couldn't be simpler; a new set of permissions to control access to each of the standard node options, on a per-content-type basis. That means a site builder can give specific user roles access to a restricted content type's options without affecting the others. In addition, there's no need to bring out the sledgehammer option of Drupal's "Administer Nodes" permission for most content creators.

Screenshot of resulting change to site

While it's possible to achieve some of the same results using custom hook_form_alter() code, the full suite of node options requires quite a bit of special logic to override effectively. Override Node Options is a quick, simple solution to the problem, and it makes a great addition to a site builder's toolbox.

Jul 09 2012
Jul 09

For Humans and Androids

Out of the box, Drupal includes many useful features that are helpful for sites where one person wears the developer, site builder, and content administrator hats all at the same time. However, some of these features could be considered dangerous when a broader group of individuals are administering a Drupal site. The Paranoia module aims to help keep your site secure by disabling places where PHP code might be executed or important data might be changed.

Installing Paranoia follows the usual steps for any other Drupal module; download to sites/all/modules, and enable it from the modules page. If the PHP module is enabled on your site, you will be warned that such content will now be "plain text" and should be audited.

PHP module and text filter is disabled

Other changes that the Paranoia module makes include:

  • Only letting user 1 (the site administrator) edit the user 1 account
  • Disabling using PHP for block visibility
  • Prevents disabling Paranoia without direct database access (or using Drush)

By default, Drupal 7 permissions tagged as being "restricted access" are prevented from accidentally being added to anonymous or authenticated users. As well, permissions exposed by other modules can be hidden entirely by implementing hook_paranoia_hide_permissions().

Paranoia is a great example of a short and simple module that gets the job done. If you're running a site where you're sharing administrative duties, consider installing it to increase your site's security.

Jul 02 2012
Jul 02

Thanks to the tireless efforts of Karen Stevenson, Drupal's Date and Calendar modules can be used to build slick agendas, calendars, to-do lists, and more. One client of ours, for example, has set up a handy view of upcoming faculty trips and outings for their university. Unfortunately, one of the most useful calendar applications can remain elusive: sending users an email when something is about to happen. That's where the Node Announce module comes in. It can use date fields on a node as cues to send out email to specified addresses -- notifying authors when their nodes will be published, attendees when events are about to occur, and so on.

Screenshot of administration screen

Setting up the module is relatively simple. Each "announcement" you set up can be associated with one content type, and one Date field attached to that content type. On that date -- or a certain number of days before it, a canned email can be fired off to the address of your choice. When combined with Drupal 7's dynamic tokens, you can also create emails that include content from the nodes themselves or other site data.

Screenshot of resulting email

It's possible to wire up similar systems (and more flexible ones) using tools like Rules or custom code. In addition, it would be great if the the module supported more flexible date options: for example, sending out messages based on the publication or creation date of a node, or the "scheduled publishing" date added by Scheduler module. Those requests aside, Node Announce is straightforward module with an active maintainer and a useful feature list.

Jun 11 2012
Jun 11

Drupal's comment module gracefully handles anonymous posters when they want to leave messages. Administrators can choose whether those comments are left unattributed, whether anonymous commenters must leave personal information like a name and an email address, and so on. When it comes to full-fledged Node content, though, Drupal's a lot less flexible: the authors of anonymously written posts show up as "Anonymous," and you'd better like it. Fortunately, fixing that problem is the purpose of the Anonymous Posting module!

Screenshot of admin page

Setting up the module is painless; just visit its settings page, choose which content types should use its expanded Anonymous Posting options, and double-check to make sure anonymous users have permissions to create those content types. Once you've done that, a special set of options will appear on that content type's settings form. They're the same options that normally apply to comments, transplanted into the world of nodes.

Once you've set it up, usage is a no-brainer. Authenticated users will be able to create nodes just as they did before, but anonymous users preparing to author a post will see a Comment-module style list of personal information fields. Name, email, and home page are all supported. The result? Easy anonymous posting, complete with "Unverified" next to the author's name to prevent visitors from impersonating registered users of the site.

Screenshot of an anonymously authored node

Anonymous Posting is available for Drupal 6 and 7. It's simple, streamlined, and because it still relies on Drupal's normal content authoring permissions it doesn't complicate the site permissions and security unnecessarily. Considering the potential for abuse of anonymous content creation, it's probably a good idea to combine this module with an anti-spam tool or a content moderation system.

Jun 07 2012
Jun 07

Login to a Drupal site without getting lost

There are a lot of different ways to configure login with Drupal. You can add a block to every page with a username and password field, a practice which I find to be ugly and distracting for anonymous site visitors. You can collapse the login block with Javascript using a module like LoginToboggan. Or you provide a link to the login page in your navigation menu somewhere. If you create a link directly to user/login, then this item will disappear for logged-in users since they don't have permission to visit.

However, due to a limitation in the menu system, most Drupal sites don't add a destination query to the login URL. This is what a Drupal URL with a destination query looks like:


The Drupal form system uses this query to direct the user to this destination after submitting a form - like the login form for example. Without it, most Drupal sites will redirect the user to their profile page after logging in.

So Drupal's default workflow tends to go like this: 1) I find the page I want to edit. 2) I realize I'm not logged in. 3) I hit the login link. 4) I log in. 5) I'm on my profile page. 6) I curse and try to find my way back to the page I wanted to edit.

This is compounded on sites like the one you're reading right now, because we don't have a login link in our navigation. It's our site and honestly, we don't want you logging into it. :-)

So how do we solve this problem for all of the ten gazillion Drupal sites out there?

Enter Jeff's Handy Dandy Drupal Login Bookmarklet! This Javascript bookmarklet will figure out if you're on a Drupal site, figure out the base path of that site (in case Drupal is installed in a subdirectory), and then redirect you to the login page with a destination query to bring you back to the current page.

Just drag this link into your browser's bookmarks bar, visit your favorite Drupal site, and click it!

For those of you interested in tweaking this sort of thing, here's the Javascript source code:

  if (typeof Drupal != 'undefined' && typeof Drupal.settings != 'undefined') {
    var u = false;
    if (typeof jQuery != 'undefined' && jQuery('body.logged-in').length) {
      if (!confirm("It looks like you're already logged in. Continue?")) {
    var l = window.location;
    var h = l.hash || '';
    var s = l.search || '';
    var b = Drupal.settings.basePath;
    var p = l.pathname.slice(b.length) || '<front>';
    window.location.href = l.protocol + "//" + l.host + b + "index.php?q=user&destination=" + escape(p + s + h);
  else {
    alert("This doesn't appear to be a Drupal site.");

Updated June 12, 2012 to add support for <front> and check of logged-in body class.

You'll need to escape it as a bookmarklet before using it as a bookmarklet though. TextMate has a nice function to do this automatically.

May 21 2012
May 21

Fixing unserialize() woes

Ever run into errors like the following on your Drupal sites?

Notice: unserialize() [function.unserialize]: Error at offset 74 of 75 bytes in variable_initialize() (line 749 of /srv/www/<sitename>/includes/bootstrap.inc).

This is a symptom of an invalid variable in the {variables} table. When the Drupal cache is cleared (or variable_set() is called), Drupal queries the variable table for all site settings and saves them in your cache for quick access. If you're getting errors like the above, odds are your variable table contains a corrupted or unserialized value.

So now that you know what the problem is, how do you solve it? For larger sites there can be hundreds, if not thousands of variables in the {variables} table. Finding the broken value can be time consuming and difficult.

Once the Variable Check module is installed, a new report is added to the Reports section in the site administration.

Invalid Variables administration screen

As we can see, Variable Check is correctly identifying an invalid string length, an unserialized value, and a missing quote from a string value.

Variable Check also adds an entry to the site status report, alerting site administrators if any invalid variables are ever added to the site. Note that Variable Check will only find variables that fail to unserialize; it can't detect variables that are syntactically correct but logically incorrect (such as a string that a module expects to be an array, or a TRUE that should be FALSE for your site).

Once a broken variable has been identified, the variable can be deleted in the user interface or with drush vdel. Or, drush can be used to correctly reset variables.

$ drush vset site_name "Kitten Emporium"

Apr 01 2012
Apr 01

The merger to end all mergers!

Today starts a new month and a fresh beginning for Drupal. After many discussions over many drinks at DrupalCon Denver, we’re proud to announce a strategic inflection point for the Drupal community. As of today, the following companies will be merging into one company - a new formidable force in the Drupal community:

These 13-ish independent companies will be joining forces to form a new paradigm-shifting meta-company: Bluemarine Synergistics. Employing over 850 individuals spread out across eight continents, the company’s name combines the popular and much-loved Drupal theme with the word “synergistic,” implying strategic partnership, enterprise-empowered logistics, and e-business efficiencies.

Finally, Drupal will have a single dominant company for enterprise customers to be their long term partner. By combining so many Drupal companies into a scalable, virtualized talent cloud, we can make it easier for customers to find us – they won’t need to shop around. And we can have a single, unified, sponsorship presence at DrupalCon and Drupal camps. It’s not only good for Drupal, it’s good for the Drupal community! Just think of the parties a company of this size can throw. It will be a lot of free beer – free, as in free beer.

With estimated combined revenues of $1.21 billion, Bluemarine Synergistics will be expanding over the coming year, hiring a 200-person sales force to create a giant “Drupal tuna net” to capture companies in new verticals such as cosmetics, agriculture, Amish social organizations, multilevel marketing, “waste management,” adult entertainment, online file transfer services, and even the hunting and fishing industries. It turns out that there are many companies, even entire industries, not yet using Drupal. For instance, the aging baby boomer population represents a huge market not yet tapped by Drupal. Bluemarine Synergistics will attack the baby boomers.

“We believe that there’s a great deal of money to be made here,” said former Lullabot CEO Jeff Robbins. “It turns out that everyone wants a website. Drupal makes websites! Bluemarine Synergistics can make your website for you, even if you’re old or Amish or whatever.”

“It’s amazing how quickly it all came together,” exclaimed Ben Finklea, former CEO of Volacci who will hold the title of Social Media Intern for the combined company. “Almost all 13 or whatever CEOs happened to be at Rock Bottom Brewery one night during Drupalcon Denver. We started doing tequila shots and yada, yada, yada – we merged! My title has changed but my job is basically the same as it always was.”

“Twice in one month... WE LOVE MERGING!” said Michael Caccavano, former President of Phase2, former CEO of Treehouse.

“Mergers are our way of showing we care about each other. We could just hang out at DrupalCon twice a year, but this way we are together all the time.” said former Phase2 Technology CEO, Jeff Walpole.

“This company has a lot of promise. It has a bright future, but I’m also proud that we’re looking back and rediscovering some of the best elements of our past. We always felt removing Bluemarine from core was a step backwards. It’s just so affirming to be a part of this giant leap forward,” said former Gorton Studios CEO Drew Gorton.

Glenn Hilton, the former CEO of ImageX Media added, "It's a great move for ImageX. All the clients we lost to our competitors, we've now gained back."

“We used to lose sleep at night, praying that potential clients would fax us their Drupal project RFPs. Now, with our powers combined, none of us will ever go hungry again!” – Aaron Stanush, former partner at Four Kitchens and newly appointed Strategy Strategist at Bluemarine Synergistics.

“Originally, our promise to the Drupal community was that we would exclusively focus on professional services. In only a couple weeks’ time, we realized that customers would appreciate a comprehensive offering that includes infrastructure. Pantheon is proud to consider itself a cornerstone in fulfilling the Bluemarine Synergistics promise. Can you put ‘cornerstone’ in italics for the press release? Thanks.” – David Strauss, former CTO at Pantheon Systems.

"All of the former Aten Design Group team members are ecstatic about becoming a part of Bluemarine Synergistics. The BS product line is so bleeding-edge. Who can say no to the 24-hour-a-day website package? Just think about it – websites, any time of the day." – Jon Clark, former Business Development Director at Aten Design Group, now Assistant to the Director of Execution, BS Products Division.

Bluemarine Synergistics finally solves the “coopetition” problem once and for all. We’re all friends. We’re all working on the same software. Why do we need to compete for employees? Why do we need to compete for clients? Heck, why do we all need to decide what to charge? Think of all the good we can do if we just band together! One big company running Drupal for the good of everyone – that’s Bluemarine Synergistics.

Company headquarters are currently being built on property located approximately two miles west of New Amsterdam, Indiana – the geographic center of all the previous headquarters when weighted by employees, revenue, and contributions to Drupal core.

Please share your excitement about Bluemarine Synergistics on your favorite social media outlets. Use the hashtag #bs4drupal because Bluemarine Synergistics is B.S. For more information, please visit http://www.bluemarinesynergistics.com. Thanks!

Feb 27 2012
Feb 27

Drupal's permission and access control system allows you to carefully control what functionality and content can be seen by different classes of users. Sometimes, though, your carefully constructed access rules can be a hindrance. What happens when you want to give just a few users temporary access to areas of the site that are normally off-limits? Letting your boss preview a new feature with a throwaway account can be useful, for example, but keeping track of those temporary accounts and ensuring that you clean them up when they're no longer needed can be a real pain. Guest Pass module solves that problem by giving privileged users the right to invite and manage special time-limited "guest accounts."

Screenshot of Guest Pass creation

Setting up Guest Pass is straightforward: drop it in, install it, and choose which user roles have the right to create new guest passes. On nodes that they own, these users will see a special "Guest Pass" tab: on it, they can create new passes by entering an email address and invitation message. The module generates a unique invitation URL and sends off an email. Once the recipient visits that URL, a fresh new Drupal user account is created for them automatically, they're granted the "Guest" user role, and redirected to the node that the guest pass was created for. Using Drupal's permissions system, you can control what content and site features those guests are able to use.

Screenshot of Guest Pass invitation email

The global Guest Pass settings page allows administrators to control which content types guest passes can be used with, the verbiage of the default invitation message, as well as the mechanism for cleaning up old guest accounts. The users who created each guest pass can go back and delete the passes (and their matching guest accounts) manually, but the module can also clean up old guest passes every few days.

Screenshot of Guest Pass administration options

The module does have some idiosyncrasies. Although guest passes are created and associated with specific nodes, they do not have any connection to per-node access controls. Every guest user who receives a pass will have the same access permissions, so there's no way to give one guest access to one node while keeping it hidden from another. It might make sense to decouple the creation of guest passes from the node page entirely, or to use Drupal 7's more robust access controls to give Guests special access just to nodes they received an explicit invitation for. In addition, there's no easy way for a user to "upgrade" a guest pass to a full user account if they want to stay. That's no problem for temporary previewing, but it makes it less useful as a tool for inviting potential new users.

Those issues aside, Guest Pass is a great tool for giving specific trusted people time-limited access to special areas of your site. Check it out!

Feb 13 2012
Feb 13

If you've ever needed to assemble an iPhone or iPad-ready Drupal site on short notice, you know that it's easy to miss some of the details. Once you've finished a responsive design and figured out how to avoid burying mobile users in heavy images, it's easy to forget the high-res Web Clip Icon used by iOS when a user saves your site to their device's home screen. Without one, a squeezed-down screenshot of your site will be displayed on their home screen. It's possible to hard-code a Web Clip Icon into your theme's markup, but with the Touch Icons module, it's as easy as uploading a custom favicon or logo image.

Screenshot of administration screen

Installing and enabling Touch Icons adds two additional checkboxes to every theme's settings page. Like the Favorite Icon and Site Logo options, activating them lets you upload a custom image file that should be used as your site's iOS home screen icon. That's it -- there's nothing more to configure or set up!

Screenshot of a site's touch icon

Technically, nothing prevents you from customizing your site's theme and embedding these touch icons yourself. If you're using an out-of-the-box Drupal theme, however, it's easy to forget. If you need to add a bit of extra polish for iOS users, this is an easy way.

Touch Icons is simple and problem-free based on our testing, but only the Drupal 6 version has an "official" release available for download on Drupal.org. The Drupal 7 version of the module is only available as a "developer release." If you're interested in helping maintain the module or want to keep track of its status for Drupal 7, check out the module's issue queue.

Jan 09 2012
Jan 09

CCK in Drupal 6 and FieldAPI in Drupal 7 give site builders a variety of structural and formatting options for carving out new content types. Multi-value fields in particular allow a node or other content element to store lists, collections of links to taxonomy terms, and more. The downside, of course, is the formatting: by default, Drupal's HTML output for multivalue text fields is a big old bag of DIVs. Taxonomy fare a bit better: they're output as proper HTML lists, a semantically proper approach. Both still require considerable CSS wrangling if you're interested in displaying multiple values simply, however. And that is where the Text Formatter module comes in.

Screenshot of administration screen

Text Formatter is a simple CCK/FieldAPI formatter for Drupal 6 and 7 that outputs multi-value text and taxonomy fields as comma delimited lists, or customizable HTML lists. It can do a few other fancy formatting tricks, as well: the last item in a comma-delimited list can be preceded by a grammatically correct 'and', and comma-delimited lists can be closed with a period. Ordered and unordered lists can also be chosen, and a custom CSS class can be specified for a particular list if you're interested in targeting special CSS rules or JavaScript behaviors. The module even allows you to format single-value long text fields as lists if they contain multiple lines of text.

Screenshot of Text Formatter in action

Text Formatters was originally part of the much older "CCK Formatters" module. Its list formatting options were by far the most popular, and were split out into a separate module for ongoing maintenance. The module is stable, trouble-free, and does just what it promises. If you need to whip a few multi-value fields into shape, check it out!

Jan 04 2012
Jan 04

Code reviews are an essential part of the software development process. Often a code review is considered to be a distinct process and kept separate from day-to-day development. At Lullabot, we consider code review to be a critical component of any development - just like QA, automated testing, and documentation. Code reviews are an acknowledgement that every developer is a human being, and humans make mistakes. No matter the skill or background of a developer, reviewing their code can only improve the final product.

Of course, code review is an integral part of Drupal development as well. The community convention is that at least two people (and often many more) should read and understand code for it to be considered for inclusion in Drupal. While contributed modules don't often have the resources for full code reviews of every patch, be sure that any module author would love reviews of their code.

What are the key components of a code review? While this is by no means a comprehensive list, here are some of the items I look for when reviewing code. Feel free to post your favourite code review tactics in the comments below.

The Story of the Code

All code committed to a project should be an atomic unit that describes:

  • Why the change was made.
  • What lines of code were changed, and how the new code works.
  • How to verify that the change actually worked.

An easy way to figure out if code meets this criteria is to read through a changeset, and answer these questions as if you've never run the code and never talked to the developer who wrote it. Verify that the code does what it says it does (at least by reading it), and that additional functionality doesn't hitch along for the ride.

Much of this information might live in ticketing systems, which is fine as long as the commit messages reference the associated ticket number. I often use commit messages similar to the following:

Ticket #1071: Convert all tabs to spaces in template.php.

Of course, with commit-friendly systems like Git there might be many small commits, and the "atomic unit" becomes a merge, and not a single commit.

Appropriate use of system APIs

Websites and applications built with Drupal have a wide array of APIs and configuration options available at many layers of the system. Many of options available at each layer of the stack can be used to achieve the same result with varying levels of success. APIs and configuration options are usually available at these components in the system stack:

  • Server software such as Apache, MySQL, and Varnish.
  • PHP and any installed PHP modules.
  • Drupal and any installed contributed modules.
  • JavaScript APIs provided by browsers or JavaScript libraries.
  • CSS for controlling visual aspects of a page.

It's important that code solve a problem at the right layer in a stack. For example, imagine you need to sort rows in a paged table. The sort could be executed:

  • As a stored procedure in MySQL (but please, please don't do this).
  • With ORDER BY and LIMIT statements manually added in the MySQL query that is executed.
  • By fetching the unordered results and sorting them manually in PHP.
  • As a call to db_query_range() that is provided by the Drupal API.
  • By sorting and filtering the actual table rows in the browser with JavaScript.

The best solution for a given use case may not be clear. Novice developers often don't understand or aren't aware of all of the layers, and code reviews can help ensure that the right changes are made in the right layer of the stack.


The security of a Drupal installation requires thought throughout each part of the system stack. Server configuration and access controls are critical components, but for code reviews it's important to focus just on the code itself. Items to watch for include:

  • Any potential SQL injection exploits. Generally this is mitigated by properly using the Drupal Database API. It's still possible to misuse the API or ignore it entirely.
  • Any potential cross-site scripting (XSS) exploits. Again, using Drupal's text APIs such as t(), check_plain(), and filter_xss() can mitigate these issues.
  • Any potential cross-site request forgery (CSRF) exploits. For example, modifying data based on a GET request could be a security issue. Converting such code to use the Form API, or to use drupal_get_token() can mitigate these issues.
  • Ensuring that user and content access controls are implemented properly. Missing node access grants on node queries is a common issue. Or, trusting user IDs passed from the client can expose data. Mitigating data exposure requires understanding both the logic of the code itself and understanding the minimum amount of data required to complete an operation.

These items are just a brief overview of potential security vulnerabilities. Drupal.org has an excellent guide to Writing secure code.

API-first design

All code should be composed of reusable functions that can be repurposed for other use without extensive refactoring. For example, most websites will have custom code that creates a custom menu item and shows a page or a form. The naïve approach is to implement hook_menu() and do something like this:

function example_menu() {
$items = array();
$items['account-balance'] = array(
'title' => 'Your account balance',
'description' => 'How much money you owe this awesome website.',
'page callback' => 'example_account_balance',
'access arguments' => array('access content'),
  );  return
example_account_balance() {
$user$output = "<h2>Your account balance</h2>";  if ($user->uid > 0) {
$output .= t('Your account balance is %balance.', array('%balance' => $user->balance));
  else {
$output .= t('You are not authorized to access this page.');

There are several issues with this code:

  • The example_account_balance() function is always tied to the currently logged in user. This means that other code would have to re-implement or refactor this function if they wanted to show the balance for a different user.
  • Access control is both done improperly and tied to the page logic. Even if access is "denied," the menu system just sees a string to return. Even though the page text indicates that access is denied, the HTTP status code will still return 200 OK.
  • The page logic (checking the account balance) is intertwined with the display itself. By not using the theme system, it's impossible to change the display without hacking the module. At most, this function should build an array of variables to pass into a theme() call.

To be "API first," this code should consist of the following functions:

  1. A page callback that accepts an $account parameter. If it's blank, it can fall back to global $user. The page URL itself should probably contain a user ID, just as a URL like user/[uid]/edit does.
  2. An access callback that checks for access to the given URL. In this case, it could probably just be set to 'user_is_logged_in', or a custom access callback if more complex logic is required.
  3. A theme function or template that would accept the string to print as a parameter. It would be responsible for setting the page heading and generating most of the HTML markup.


Code isn't done until it's documented. At a basic level, that means that every function should have appropriate PHPDoc headings with information about what the function does, what parameters it accepts, and what it returns. It's just as important to verify that the documentation matches what the function actually does. Inline comments should be added as appropriate to describe particularly tweaky sections of code. Any hacks to work around bugs in other modules should include a comment describing the bug and a link to the upstream ticket or issue. If code is adding any new system variables (with variable_set() and variable_get(), those should be documented if they are not exposed through a UI. For new modules, a README.txt should be included to describe the overall purpose of the module as well as any installation instructions.

Unit and Functional Tests

If a project is using SimpleTest or Selenium, code should never be committed without the associated tests or changes to existing tests. "I'll add tests later" is a common phrase when a project is under a deadline, but those are exactly the times when automated testing is most important. Writing and validating automated tests is beyond the scope of this article, but for more information check out the SimpleTest tutorial on Drupal.org.

Code Style and Standards

Finally, code should follow whatever code standards have been decided for the project. Typically Drupal projects use Drupal's code standards to simplify integration of code from various sources. Following code standards reduces the effort required to read code and ensures that it's easy to identify components of code. It can also help reduce issues with merging code written by developers on different operating systems. If code is being submitted by developers that frequently breaks code standards, it can usually be resolved with a bit of education and text editor configuration. For more information about code standards, check out the Coding standards page on drupal.org, the Coder module, and the Drupal Code Sniffer module.

Next Steps

Code review is an ongoing process, and one that should be integrated into your development workflow. Code reviews don't just make for better code now; they push your team to write better code in the future. For more information about reviewing code, take a look at the How to review Full Project applications page on Drupal.org and the pages it links to.

Dec 26 2011
Dec 26

Here at Lullabot Headquarters, we try to make sure that each week's Module Monday article highlights a lesser-known tool that's simple, useful, and efficient. In honor of the holiday season, though, this week will show off a Drupal module that's 100% fun: Konami Code!

If you played video games in the 80s, you might remember the infamous secret code that could be entered on the first screen of Contra and other games produced by Konami. An entire generation of gamers learned that up-up-down-down-left-right-left-right-b-a was the key to eternal life, and more recently the code was the key to activating east eggs on web sites like Facebook.com and Marvel.com. Now, thanks to the Konami Code module, you can hide the easter egg of your choice on any Drupal site using the same key combination.

Screenshot of the Konami Code module's configuration screen

The module sports a staggering number of configuration options, most centered around what should happen when visitors to your site enter the code. Would you like to redirect them to another URL? No problem. Would you like jQuery-powered snow to fall on the page, turning your site's design into a winter wonderland? Easy. Covering the page with bacon, launching an in-browser game of Asteroids, and popping up an alert box containing custom text are all easy to do with the module. You can also customize the exact key commands used to trigger the easter egg.

Screenshot of Drupal content experiencing heavy precipitation, thanks to the Konami Code

Hiding a secret picture of a unicorn on your web site and activating it with the Konami Code may not be mission-critical functionality, but it's a traditionally nerdy way to sneak some light-hearted fun onto a small site. Check it out -- and enjoy the holidays!

Mar 07 2010
Mar 07

It turns out that imagex had a security issue in it. The maintainer refused to fix it, so this module has now been unpublished. I built plupload for the same purpose - screencast coming soon!

This video shows how to use the Multiple Image Upload, Views and Views Bulk Operations modules to create a "multiple image upload and tag" tool. The View used in this video is attached as a text file which can be imported into your site using the Views import tool.


6 minutes

Feb 04 2010
Feb 04

The brand spanking new Favorites module is a great way for users of your site to indicate which pages on your site that they truly like. Developed by ezra-g as part of our work for the new IxDA.org, Favorites for Drupal 6.x takes over for a module that Jeff Robbins originally created.

I created this screencast to show how to enable and use the module. I hope you enjoy it!


4 minutes

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web