Fixing Shipcalc Module Bug is an Example of Overriding Drupal Forms.

A customer on a newly launched Drupal e-commerce site I produced reported the following error:

Please enter a valid ZIP Code for the sender. (error -2147219498) usps configuration error. Please notify the site administrator.

…which occurred during the checkout process and only happened when an zip code contained a “+ 4″ code at the end.

Of course, I often find Google to be the best debugging tool of all, and I quickly found this post containing a workaround by Kenneth Bartlett that not only made it so I didn’t have to untangle the shipcalc module’s code, which would likely mean debugging Web Services calls to USPS, but its actually a pretty good solution in its own right, I think.

The only thing I didn’t like about it was that it directly patched an e-commerce module file at modules/ecommerce/address/address.module. Whenever I use a piece of customizable software like Drupal (or WordPress, osCommerce, etc.) I avoid directly patching both the core code and any third party modules, because this creates a maintenance burden for me when I want to upgrade the core software or an affected module, because I could potentially wipe out these patches. making the bugs reappear. I have my hands full maintaining my own code, I don’t want to worry about modules I didn’t write.

Now, the obvious exception to this is when the bug is both known and fixed in the development version of the third party code. Then I will gladly apply the patch to the existing code knowing that when I upgrade that code, I won’t have to worry about protecting it from being overwritten. I can just “fix it and forget it”.

Otherwise, what I want to do is make the smallest change possible to fix the problem without creating new bugs, and I want to do it from within code that I am already maintaining anyway.

Luckily, Drupal is very cleanly designed with well defined ways of customizing existing code to maximize both reuse and flexibility. There are actually a number of ways you can customize form functionality in your own code depending on what you want to do, including adding your own validations and submission functions.

For this site, I had both a custom theme and custom module, but because all we are trying to accomplish is limiting the max length of the zip code entry text field, I decided that overriding this field in my theme was appropriate.

The first thing I needed to know was the form ID of the form. Every form in Drupal has an associated form ID, and the easiest way to find it is to browse to the form page, view source, and find the corresponding hidden form field value for that form named “form_id”. In this case, the form ID was “address_form”.

With this information in hand, I can create a function in my theme to override the zip code field definition. The name of this function follows a convention based on the form ID, and again, there are several such naming conventions you could follow depending on what you want to do. This job was simple enough that I didn’t have to sweat these details and just took the most generic approach, calling my function “theme_address_form”.

Then it was just a matter of changing the zip code definition:

function theme_address_form($form) { // satisfy Drupal form API $form[‘zip’][‘#id’] = ‘edit-zip’; $form[‘zip’][‘#name’] = ‘zip’; $form[‘zip’][‘#parents’] = array(); // the desired changes $form[‘zip’][‘#size’] = 5; $form[‘zip’][‘#maxlength’] = 5; // proceed normally return drupal_render($form);}

As you see, I did make some minor changes to Keith’s original fix, although the effect is the same. Instead of replicating the entire ‘zip’ field definition, I just changed the individual elements of the definition. The first three lines in the function are additions to make Drupal happy, otherwise the field will be output without ‘id’ and ‘name’ attributes and an error will occur because it expects ‘#parents’ to be set to an array, even if its an empty array.

Then I replaced the ‘#size’ and ‘#maxlength’ elements with my desired changes. There won’t be a “+ 4″ error if people can’t enter “+ 4″ codes. Finally, I render the form normally.

Its as simple as that: I made the smallest change possible for the desired effect, and I did it without injecting code into a third party application or module. Drupal was designed to make just these types of changes painless.

Related Post