Tomorrow’s Internet

In the 14 years I’ve been doing web development, I’ve seen the internet become so ubiquitous that it’s found its way into every aspect of our lives. It’s humanity’s shiny toy. We fumbled with it for awhile before we figured out how to really use it, and we’re still dreaming up new ways to play with it.

We’re all familiar with the trends that drive the internet’s growth. Over time, computers are getting smaller and faster, more than ever thanks to the rise of mobile computing. New technologies are being produced to take advantage of these ever-expanding capabilities, spurred on by crowd-funding, which is a new idea in and of itself. Eventually, those technologies move from high-priced gadgets for professionals and enthusiasts into affordable products for consumers at large. It’s a self-perpetuating cycle of technological advancement, innovation, and consumer adoption. It’s also the reason science fiction tends to become reality after a few decades.

If you accept these facts, then predicting the future is as simple as examining the emerging technologies of today, overlaying the data processing capabilities of tomorrow, and applying the polish of consumerism. With that logic in mind, here are my predictions for the internet of tomorrow:

What does it mean for us web developers? On the bright side, our jobs are safe. Demand for primitive internet presences (e.g., websites) are sure to remain high for backwards compatibility and for users who prefer simpler, 2D experiences. However, much like responsive design, we’ll need to become masters of new standards, such as 3D modeling, in order to meet the new demand for augmented reality elements. It won’t be enough to know HTML any more; we’ll need to become the architects of our clients’ entire virtual presence or risk being left in the wake of the new technology.

Make no mistake, though. These things aren’t just coming; they’re already here. Some of this may sound like Jetsons-esque “flying cars” talk, but the technology for everything I’ve mentioned already exists. It’s only a matter of time before it gets combined into something resembling augmented reality. When it does, it’ll be a brave new world, a lot like the old one but with a tantalizing virtual coating.

Remove Node Lists from Taxonomy Pages in Drupal 7

If you use Drupal, you can’t help but love the Taxonomy module. After all, categorizing content goes hand in hand with creating it or managing it, and Taxonomy gives us a nice, flexible framework, especially when you throw fields into the mix.

Unfortunately, every taxonomy term page comes with a default list of all the content classified with that term. Sometimes you might want this, but sometimes you might not. I’ve run into a few situations in which I needed tighter control over the term page display, like that provided by Views, without wanting to override the entire page.

Here’s the snippet of code I created to deal with those situations. Just put the following in the template.php file of your theme folder:

function THEMENAME_preprocess_page(&$vars){
  if (arg(0) == ‘taxonomy’ && arg(1) == ‘term’ && is_numeric(arg(2))){

This will remove the default content list, as well as the pager and “No content has been classified with this term” text if either is present. On a default installation, that sets the page back to a blank slate, like an ordinary content page, so you can play around with it from there to your heart’s content.

jQuery Default Form Text Function

Often times, in place of labels, designers will choose to put default text in a form field to denote the information that it should contain. This is good design and usability, but it also creates some functional problems. Obviously, the text should disappear when the field is in focus, but what happens if the user clicks away without entering anything, or submits the form before filling in the field?

This handy jQuery function solves those problems. Default text will appear in the field whenever it is empty and not in focus. The user can click it to remove the text, then click away to reveal it again. If the field has been filled out, nothing happens. As a bonus, if the form in question is submitted with default values, those are cleared before the submission takes place to allow for proper validation.

function default_text(selector, text){
  element = $(selector);
  if (element.val() == ''){
    if ($(this).val() == text){
    if ($(this).val() == ''){
    if (element.val() == text){

  default_text('#your_form_element_id', 'Your default text');

How to Enable Ubercart Product Image Zoom with Gallery Thumbnails

In my experience, ecommerce websites are their own beasts, with all sorts of specialized functionality that doesn’t get requested on other websites. One of the most frequent requests, and often times one of the most difficult to fulfill, is enabling product image zoom functionality along with gallery thumbnails that can seamlessly swap out the main image. Here is one way to accomplish that on a Drupal 6 website with Ubercart.

  1. Install the necessary modules. For this solution, you’re going to need CCK, ImageField, ImageCache, and Cloud Zoom (I used to prefer jQZoom, but found it to have less compatibility in WebKit browsers).
  2. Set up your image field. The code provided below is designed to work with the default image handling field creating by Ubercart, but it can work just as well with any CCK image field. Just be sure to swap out the $node->field_image_cache variable with the name of your own field if you’re using something different.
  3. Set up your ImageCache presets. You’re going to need three. Again, the solution below is tailored for use with product images in Ubercart, so I’ve named them accordingly. “product_full” is the main image displayed to the user, “product_zoom” is the larger image shown in the zoom window, and “product_thumbnail” is the gallery thumbnail that allows the user to swap out the main image. You can name these whatever you like; just be sure to change their names in the code as well.
  4. Stop the field from displaying. By default, Cloud Zoom can automatically display the image and zoom window without any need to mess with template files. This is very handy, but it doesn’t support gallery thumbnails, so we’ll need to disable the default behavior. Go into Administer > Content Management > Content Types > Manage fields > Display fields and change the Label, Teaser, and Full node drop-downs for your image field to . Be sure not to click the Exclude boxes, or else the template modifications below will not work properly.
  5. Add this code to your theme file. In the case of Ubercart, this goes in node-product.tpl.php where you’d like the images to appear. If you’re using a different content type, use that in place of product. And again, be sure to switch out the image field variable name or the ImageCache preset names if you’re using something different.

    drupal_add_js(drupal_get_path('module', 'cloud_zoom') . '/cloud-zoom/cloud-zoom.1.0.2.min.js');
    drupal_add_css(drupal_get_path('module', 'cloud_zoom') . '/cloud-zoom/cloud-zoom.css');
    if (is_array($node->field_image_cache) && count($node->field_image_cache) > 0 && strlen($node->field_image_cache[0]) > 0){

    // Display the primary image.
    echo l(theme('imagecache', 'product_full', $node->field_image_cache[0]['filepath'], $node->field_image_cache[0]['data']['alt'], $node->field_image_cache[0]['data']['title']), imagecache_create_path('product_zoom', $node->field_image_cache[0]['filepath']), array('attributes' => array('class' => 'cloud-zoom', 'id' => 'zoom1'), 'html' => TRUE));

    // Display the gallery thumbnails.
    $num_images = count($node->field_image_cache);
    if ($num_images > 1){
    for ($i = 0; $i < $num_images; $i++){
    echo '' . theme('imagecache', 'product_thumbnail', $node->field_image_cache[$i]['filepath']) . '';

  6. Stylize to taste. With a bit of added coding and some CSS, you can make the final product display however you like. For example, I like to put the gallery thumbnails into an unordered list and float them beneath the main image for ease of usability. Your needs may vary.

How to Add Variations to a Drupal Theme

Recently, I did work for a few clients who needed several very similar websites launched in a single project, each of which using an almost identical (yet subtly different) theme. As I started configuring them on Drupal multi-site installations, it got me thinking: Is there a way to take advantage of the same sort of code reuse within a theme?

There are already options for this, of course, such as sub-themes or the Color module. In my case, however, I decided to try something a little different: I used a custom theme setting to add a CSS class to the body tag, then created the theme variations with pure CSS. Here’s how I did it.

Step One: Set Up the Advanced Theme Setting

In case you’re a Drupal themer who doesn’t know this trick, it’s a life-saver. You can configure your theme with a form to collect custom settings, then use those settings in the theme itself. I like to use this for things like phone numbers that don’t deserve their own block region but need to be configurable by the client nonetheless.

There’s a great Drupal article on advanced theme settings, which I won’t bother repeating. As far as theme variants go, all you have to do is include the following code in the theme_settings.php file of your theme folder:

function themename_settings($saved_settings){
$defaults = array(
'variant' => 'default'
$settings = array_merge($defaults, $saved_settings);

$form['variant'] = array(
'#title' => t('Variant'),
'#type' => 'select',
'#default_value' => array($settings['variant']),
'#options' => array(
'default' => 'Default',
'variant_1' => 'Variant #1',
'variant_2' => 'Variant #2',
'variant_3' => 'Variant #3'

return $form;

This will create a drop-down selection menu on your theme configuration page that allows you to select the desired variant. Be sure to change the keys and values in the #options array to include the CSS class and variant names you want.

Step Two: Hook the Variant Setting into the Template Files

Now that the variant can be defined, it’s time to dynamically include it in your template files. This is accomplished with the theme_get_setting() function. Include the following code at the top of your page.tpl.php file (and any other relevant template files):

$variant = theme_get_setting('variant');
if ($variant == 'default'){

Then, on the body tag in each template, include code to insert the variant as a CSS class:


If you want, you can do other useful things with the $variant variable. For example, I took it a step farther and created image subfolders at theme_folder/images/$variant. That way, if I had images that needed to vary, all I had to do was name the images the same and include $variant in the image src attribute.

Step Three: Add CSS to Customize Each Variant

Once the body is being classed according to the theme variant setting, you can do whatever you like to customize each variant. Simply add CSS to your style.css file in order to tweak the theme’s appearance according to the new body class. For example, you might adjust the font face and color of each variant:

#content { color:#000; font-family:Arial; }
.variant_1 #content { color:#F00; font-family:Helvetica; }
.variant_2 #content { color:#00F; font-family:Verdana; }

Possible Uses

The main use of this technique is to provide a fast, easy way to create minor variations in a single Drupal theme. You might add some seasonal stylization for a holiday variant, for example. Or, as in my case, you might have a few small differences between sites using the same theme and want to keep a common code base for ease of maintenance.

Anything more than that and you’re probably better off using one of the aforementioned techniques, such as sub-theming or the Color module. It’s really just a matter of how different your variations are going to be.

Why Never to Launch a Site on Friday Afternoon

Imagine sitting in mission control as a rocket is launched into space. The countdown initiates. “10, 9, 8…” The boosters engage. The astronaut comes over the com to confirm final checks. “7, 6, 5…” Everything is a green light. The launch crew sits on the edge of their seats. “4, 3, 2…” The moment is finally upon us, and then… quitting time. Just as the rocket is about to launch, everyone gets up from their desks and heads home for the weekend.

Sounds pretty strange, doesn’t it? Why would anyone do something so reckless? Doesn’t it make more sense to give launch the time and attention it deserves? After all, if everyone walks away right before lift off, they may miss a critical moment that could make or break the whole operation.

That, ladies and gentlemen, is exactly what happens when you try to launch a website on a Friday afternoon. You initiate the countdown and walk away, naively trusting that everything will go smoothly. No verification of success. No post-launch QA. You just push the button and go home for the weekend.

You’d think this would be common sense. You’d think any good web development company would know better than to do it like this. Regrettably, you’d be wrong. This has happened at every web shop I’ve worked in, not just once, but often. Clients have been allowed to say the word “Go” at the worst possible moments, thinking it’s as simple as pushing a button and letting everything magically work out.

The thing is, clients don’t know any better. They don’t do this for a living. It’s the job of their web development team to explain that launching a website is a non-trivial process that takes time and attention, that launching without a human being present to fix things when they inevitably go wrong means they’re stuck with a broken website all weekend, that unexpected glitches must be factored in, and that it’s a bad idea for their company and their brand to do otherwise. Anything less is reckless.

The alternative, of course, is a broken website that languishes for days while clients gnash their teeth, pull their hair out, and make angry phone calls at 3:00am because their brand new website isn’t working right. This hurts not only the client’s business, but the web shop’s business, too.

So the next time you’re working with a client who insists on launching late on Friday (or you happen to be that client), do everyone a favor. Stop, breathe, and ask if it can wait until Monday. 99% of the time, it can, and as I’ve said, it really, really should, for everyone’s sake.

Code HTML Email Templates by Breaking the Rules

If you’re anything like me, the first time someone told you to make an email template, you thought, “Piece of cake!” After all, emails use HTML (or the types that needs templates do, at any rate), and HTML is a cinch, right?

As it turns out, you’d be wrong. HTML is a cinch, but the truth is, the more you know about proper HTML coding standards, the harder it is to make a functional email template. That’s because the only way to write them is to break all of those pretty rules you spent so long mastering. Here’s the breakdown:

  • Only use inline styles, if you even use them at all. External or embedded stylesheets will almost certainly be stripped out. Some email clients allow you to declare your styles in the document, but support for this is spotty at best. The only way to guarantee that your styles get parsed is to place them into style attributes on each and every element. Even then, be aware that many useful style attributes (background and position come to mind) are not widely supported.
  • Use tables for layout. As I mentioned above, email clients don’t generally support CSS positioning. The best way to ensure consistent display across clients is to use tables.
  • Exclude the HTML, head, and body tags. A lot of email clients strip them out anyway.
  • Exclude forms and JavaScript. Email clients will ruthlessly omit your dynamic functionality, and your email’s spam profile will be much higher for the attempt.
  • Don’t worry about SEO. Emails don’t get indexed, anyway, so the code can (and will be) as cluttered as you like. Make sure it can still be parsed by screen readers, of course; we wouldn’t want to turn away disabled subscribers. Just don’t concern yourself with making an email rank.

Why are the rules set this way? I blame the proliferation of spam and the lack of standards between email clients. HTML is great, but it gives spammers too much control, and the knee-jerk response is to strip out everything until you’re left with… well, this. Don’t believe me? Try testing your email template on the dozens (probably hundreds) of email clients in use. And you thought cross-browser compatibility testing was bad…

So, blasphemy though it may be to us coding purists, these are the standards you have to keep in mind when coding email templates. As a rule of thumb, just break every rule in the book and you’ll be on the right track. And if that makes you feel dirty, you can always read a good book on HTML 5 for absolution. 😉

Elsewhere: So You’ve Got a Drupal Website… Now What? (Part Two: Learning the Lingo)

I just posted So You’ve Got a Drupal Website… Now What? (Part Two: Learning the Lingo) on

In this series, I walk you through the basics of using your shiny new Drupal website. In part one, I explained what Drupal is and why it’s awesome. We’ll get into working with Drupal in the next section. Before we can walk the Drupal walk, however, we need to learn to talk the Drupal talk.

Read the whole article on

Elsewhere: So You’ve Got a Drupal Website… Now What? (Part One: What is Drupal)

I just posted So You’ve Got a Drupal Website… Now What? (Part One: What is Drupal) on

It’s shiny. It’s new. And it’s totally mind-boggling how much you can do with it. The only trouble is, you have no idea where to start. In this series, I’ll walk you through all the useful bits and bobs in your new Drupal site, how to use them, and all of the situationally useful extra stuff you can safely ignore 99% of the time.

Read the whole article on

Attach Files to Taxonomy Terms in Drupal

From what I can tell, there are plenty of ways to attach files to nodes in Drupal, and even a few ways to attach them to users, but none that I could find to attach them to taxonomy terms (images through the Taxonomy Image module, for sure, but not files in general). My guess is that there just aren’t enough people who need to do so.

In a recent project, however, I found myself needing just that. The client in question was using a vocabulary of fonts that had to be associated with their respective font files for JavaScript. After beating my head against the problem for awhile, I managed to figure out a solution. Instead of attaching a file directly to the taxonomy term, I assigned the same vocabulary to a new content type to hold the attachment. Here’s how it works:

  1. Go to Administer > Site building > Modules and make sure the core Taxonomy and Upload modules are enabled.
  2. Go to Administer > Content management > Content types and click the link at the bottom to Add a new content type.
  3. Give your new content type an intuitive name (e.g., Font File) and enable attachments under Workflow settings. Configure the other settings as you see fit and hit Save.
  4. Go to Administer > Content management > Taxonomy and edit the vocabulary for which the file attachments are intended (e.g., Fonts). Check the box next to your new content type and click Save.

Great! Now you have a way of associating a term with a file, albeit indirectly through a node. How you use that information will, of course, vary. In my case, the font files needed to be populated into a drop-down list of font choices for use by JavaScript. Here’s how you might go about accessing the attachment from the database:

// Fetch the file path of the most recently uploaded file attached to a node that shares the given term
$attachment_path = db_result(db_query("

SELECT filepath FROM {files} f JOIN {upload} u ON f.fid = u.fid JOIN {node} n ON u.vid = n.vid JOIN {term_node} tn ON n.vid = tn.vid WHERE n.type = '%s' AND tn.tid = %d ORDER BY f.timestamp DESC LIMIT 1



Of course, the best solution would be to create a custom module to handle all of this. In my case, there simply wasn’t enough time for that. I invite some enterprising developer to invalidate my technique by creating a module that allows file attachments on taxonomy terms. Until then, I hope someone finds my roundabout hack useful.