Aug 15 2005
Aug 15

Everyone using Drupal should upgrade ASAP to the new Drupal 4.6.3 (or 4.5.5 if you're running 4.5.x), as a serious security vulnerability has been found in the third-party XML-RPC library Drupal ships with. I sent the security advisory to Full-Disclosure, Bugtraq and the phpsec mailing lists, so hopefully everyone will notice and upgrade.

Aug 09 2005
Aug 09

I released a first version of my Drupal security.module yesterday. The module is sort of an intrusion detection system for Drupal sites. It helps the site admin to check and ensure the security of his Drupal installation. Read my original announcement for more details.

The code is in ALPHA stage, so don't expect everything to work, yet.

Jul 14 2005
Jul 14

Drupal Donations Thanks Poster

Lots of good news for the Drupal project:

The future looks bright...

Jul 10 2005
Jul 10

The Drupal website has been down for two days now. They haven't received a response from support and hence cannot fix it (sounds familiar to me).

On the long run, Drupal will migrate to the Open Source Lab (OSL) which offers lots of services and already hosts many popular Open Source projects like Mozilla, Apache, and Debian.

To be able to do this, they need a new server (free rack space and bandwidth are provided by OSL) for which they are seeking donations now.
It's also planned to create a non-profit organization which will hold the funds, so the donations will be tax-deductible...

Jul 03 2005
Jul 03

The Bryght guys (a bunch of very competent Drupal developers) seem to have a lot of fun while coding...

Jul 01 2005
Jul 01

As most of you probably noticed, the design and structure of my homepage and my blog changed quite a bit a few days ago.
That was me upgrading to Drupal 4.6.1, which makes my life a lot easier, has a bunch of new features (e.g. my blog now has tags) and bugfixes, and most importantly fixes a serious security issue.

Two days ago I tried to help a bit with the new Drupal 4.6.2 release, which mainly fixes two major security problems. The first one is an issue with incorrect input validation, resulting in the DRUPAL-SA-2005-002 security advisory. The second one fixes a problem in the XML-RPC library shipped with Drupal (and Wordpress, and PostNuke, and...), resulting in DRUPAL-SA-2005-003.
It was quite a fun experience for me, the release was coordinated and discussed on IRC, we had lots of peer-review of the advisories and release-announcement, testing the patches etc. Thanks to all who participated and made this such a great experience.

Jun 24 2005
Jun 24

Woah, three of the modules I've written for Drupal are among the top 12 downloaded modules.

May 05 2005
May 05

I'm happy to announce that my (German) Drupal article has now been translated (not by me) and will be published tomorrow in Issue 55 of the (English) Linux Magazine.

It doesn't appear to be available online, unfortunately.

Apr 06 2005
Apr 06

Jonathan Chaffer has written a very interesting article which explains how the CMS Drupal (which powers this site, btw.) uses many OOP principles and Design Patterns without using PHP's class keyword. It's written purely procedural, while still using the best features the OOP world has to offer.

The main message IHMO is this: OOP != classes.

Mar 26 2005
Mar 26

I was having trouble getting SSIs to work on this site. Usually my host is good about stuff like that, but maybe they were having an off week. Unfortunately, I really wanted to include a list of links on my sidebar, but didn't want to hardcode them in as I expect them to change fairly frequently. I needed to find a work-around.

I went looking for a solution on some of the MT sites I'd discovered, but didn't find anything that really satisfied me. I didn't want to set up another blog. SSIs weren't working. I was stumped.

Then I reread parts of the MT manual and saw the answer. Modules. Wow. I was wondering what those things were.

All I had to do was format my two lists (with <ul> and <li>, but no other code). Then I created separate module templates for each list. Finally I put the line

<$MTInclude module="NameOfMyModule"$>

on each of my templates where I wanted a list to appear. And that was it.

Now each time I want to updated a link list, I only have to change the one module and my list will be updated throughout the site.


Mar 23 2005
Mar 23

For a number of years now I've been a Gossamer Threads' Links devotee. Some people sit around on Sundays doing the crossword puzzle. I like messing with the code in Links. There are all sorts of fun mods to add to the basic script, and I have to admit I've tried most of them. But lately, with a new business, I've been too busy to fiddle with codes and mods. In fact, I've gradually weaned myself off Links. I was feeling pretty good about it, too.

So, wouldn't you know it? About a month ago someone suggested I subscribe to their RSS feed. Huh? It sounded like something from the ICU ("Oh, yes, they finally took Harold off his RSS feed. He'll be eating solid foods again any day now.") Then Nick Usborne of Excess Voice did a piece on RSS and invited people to try signing up for Bloglines and giving his RSS feed a try.

A little uncertainly, I bumbled through the Bloglines registration, not sure what the heck they were talking about half the time. Would I find myself on life support by the end or, worse, inundated with spam? But once I saw some of my favorite e-newsletters listed, I started to get the hang of it. Pretty soon I was signing up for feeds right and left, feeling like a kid let loose in a candy store—Yeah!, I'll take three of those!

Well, of course, this only made me more curious about this whole RSS thing. Who is putting out all this information? Why do they do it? How do they do it? "Blogging"? You're kidding, right?

Still, I can't very well call myself a proficient web designer if I don't even know what a blogger is, can I? So I decided I'd better find out what it's all about. Better yet, let's see how they do it. In fact, let's take a look at some of the software they use like WordPress and Movable Type. What's that you say? Configurable? Plugins? You mean… [brief moment of respectful silence] Mods!?

And so, another MT addict is born. I'd finally kicked the Links habit, only to be introduced to Movable Type. Plugin heaven.

It's a dangerous world out here.

Mar 16 2005
Mar 16 currently carries a story by its author Dries Buytaert where he compares the popularity of CMSes (and blogging systems and forums) using the Alexa traffic ranking service. There's several nice graphs included, so have a look.
Also, there's a similar service called which can be used to create nice graphs from the number of hits Google returns for a given keyword. See the graph for Drupal for an example.

(via Peter van I. via email and

Mar 11 2005
Mar 11


I am somewhat proud to announce that an article written by me about the free CMS Drupal, has been published by the German Linux journal Linux-Magazin. It's available in their Sonderheft Linux-Magazin 2/2005: Web Edition (a special issue about web publishing).
Unfortunately the article is not available online, so you'll have to buy the magazine to read it.

My article gives a broad introduction to Drupal, covering the installation (and some troubleshooting) as well as the basic concepts like nodes, users, roles, permissions, themes, modules etc. I briefly introduce some important contributed modules, explain how one usually installs modules and give a short overview of what will be new in the next release, Drupal 4.6. There's also a tiny section about the history of Drupal, and I provided links to some interesting Drupal-stuff like the Custom Blocks repository (which has recently moved, so the URL in the article is wrong), the Drupal Theme Garden and the Drupal API documentation.

If you happen to have read the article, I'd be happy to get some feedback.

Mar 09 2005
Mar 09

The first release candidate of of Drupal 4.6 is available. You can already check out the soon-to-be-released new version of Drupal, but bear in mind that some bugs and issues will have to be resolved until the final release.

There will be some great new features and improvements, check out the ChangeLog.

Jul 24 2004
Jul 24

My latest Drupal project is a collaboration with John VanDyk, author of the Metadata Plugin for Manila. John also wrote a great walkthrough of Drupal's life-cycle that's worth reading, especially if you've never stepped through Drupal before. I've known and worked with John for many years, and this project is something we've wanted to build for quite a long time. It's a metadata-centric approach to content management.

Most content management systems use metadata only at the presentation level, lumping it in the same category as 'user navigational aids', such as breadcrumb trails. We feel metadata can easily drive both content AND functionality given a solid framework of schemas, metatypes and actions. In otherwards, metadata becomes a collection of tools used to shape the presentation and behavior of your site. Drupal has a foot forward in this arena with the taxonomy module. Our goal is to extend taxonomy module in three areas:

  1. Open vocabularies. User's should be allowed to add terms if they have permission to do so.
  2. The ability to render terms as any HTML form field, instead of select boxes only.
  3. If a vocabulary is storing numeric information, it should be stored in the database as a numeric type. The same holds true for string terms.

On a larger scale, we're also creating the ability to add metadata schemas to existing node types. We're not declaring new node types, but extending them with user-defined attributes (aka vocabularies). Say for example you want weblog entries with 'word of the day' and 'song of the day' features, here's how you'd do it:

  1. Add a new metatype (aka vocabulary) called 'word of the day'. Choose the string data type and specify that it should be displayed as a textfield. Optionally assign actions to the metatypes, such as validators and display properties. Do the same for 'song of the day'
  2. Create a new schema that extends the original blog node type. Name it and add your two metatypes.
  3. All schemas you create are visible on the 'create content' page. Click on your new blog schema and you'll notice the 'word of the day' and 'song of the day' form fields are present. Your blog entry is the same as any other blog entry except you've extended the definition of what it means to be a blog. The behavior of this metadata is much like the current behavior of taxonomy views, allowing you to list all content with like terms.

And there's no reason why you can't have multiple blog schemas as well! Now that makes life interesting, doesn't it? Imagine a corporate intranet where each department wants to use blogs to track different types of information. Schemas would make this approach much easier than manually writing different blog modules for each department.

Hold on, there's more. Once a metatype is created, it can be attached to any number of schemas. For example a keywords metatype will probably have the same function for most schemas. It is even possible to have hierarchial metadata values since we're building on top of Drupal's taxonomy system.

So far I have been very surprised how little the Drupal core code has been modified for this project. At this stage I can't offer any timeline on when we'll be finished, but if you're coming to OSCON, look us up and we'll be glad to show you a demo :-)

Jun 24 2004
Jun 24

The img_assist module has been added to the Drupal contributions repository and with it several updates.

  • Previewing image thumbnails can be filtered by image categories so you don't have to view them all at once. (screenshots)
  • The generated code snippet can be viewed before it is inserted. This allows you to manually copy the code and paste it somewhere else.
  • There are now Drupal 4.4 and CVS HEAD versions of this module.

Here's the official Drupal project page to download the module.

Jun 09 2004
Jun 09

The latest module i've concocted for the next release of Drupal is designed to make adding images to content easy without getting too caught up in HTML. It acts as a frontend to image.module, and thus does not upload images by itself. Here are the screenshots.

So what makes this different from all the other image-adding modules? I have no idea, i didn't look. But here's a list of things this one does:

Quickly add images

Step 1. Choose a thumbnail
Step 2. Click 'Insert image snippet'

Add borders, captions, adjust alignment and more...

With no need for any third party libraries.

Resizing maintains aspect ratio

When resizing an image, the dimensions of the image are locked by default in order to maintain the aspect ratio.

You control the output

The HTML code snippet generated by this module is user-defined. For example you can make all your images float to the right by default, or even link to the larger image.

Track where images are used

This module records to locations of all the links it generates. This allows you to generate blocks that inform your users where else this image appears. You can do this by enabling the 'Image reference' block. The block will be visible on the node/view/ page of any image with references.

Creates pure HTML with no Drupal filters

Previously in order to add an in-line image to a node you either had to use an image filter or straight HTML. This module creates the best of both worlds. The end result is HTML that does not need to go through the Drupal's sometimes expensive filtering system. And better yet, if you ever update your original image with a new one, the image links will still work. This is because the generated code snippet is using a reference to the image ID instead of the actual file.

Image Preview

You can view what the image will look like before changes are committed.

Only an interface

This module does not upload images, it only inserts images that are already on the server into content such as blogs and stories or any node type. This makes it a great interface for the image module.

So, in order to use this module, either you need the aforementioned image module installed or you need another module that does the following:

  1. Stores images as nodes
  2. Creates a database table called 'image' with at least the following column names:
    • image_path: the path to the image from the Drupal root.
    • width: image width
    • height: image height
    • nid: the node id of the image. Images must be nodes.

And now the download link:

Jan 06 2004
Jan 06

This tutorial is designed for the CVS HEAD tree as of Dec 30, 2003.

This tutorial assumes that you have successfully installed drupal and are ready to creat your first user account. If you haven't made it this far yet, be sure to revisit the INSTALL file that comes with drupal as well as the online documentation.

Creating the superuser account

The first step after a successful installation is to create the superuser account. This account allows an user to bypass all Drupal permissions and perform any action on the site. Only one account can be the superuser account, and it is strongly recommended that this account is used only when necessary and not for everyday use. The first account you create in Drupal will be the superuser account.

Go to the main page of your Drupal site and click the Create new account link

Click the Create new account link

Enter an username and E-mail address for the superuser, which in most cases be yourself. After clicking the Create new account button and submitting the information, you receive a special message about the power of the account just created and a login button to click and enter the site.

After you login, you probably want to change your password to something that's a bit more personal. Change your password and any other account settings you wish. When you're finished here, we jump into administering the site.

Where's the Admin Interface?

The admin interface is accessible in your user block which organizes all the actions you can perform on the site. Since your the superuser, you have access to the admin interface via the Administer link.

Accessing the admin interface.

You'll notice that in the admin interface the site still maintains the same look and feel of the current theme.

Since your logged in as superuser, you get the 'Administer' link which is the entry point into the admin interface. Go ahead and click on it. By default the admin interface displays a briefing of the most recent system events on your site. These are called messages, and will come in very handy when users are reporting problems and detecting suspicious activity on the site.

Underneath the Administer navigation tree is seven links. Here is an overview of each section:

  • content- manage all content that has been posted to the site. You can also navigate to a particular item of content and edit from there as well. In most cases this is an easier approach unless you need to do batch content editing. You can also set global properties for your content here, such as which content types (such as books, stories, and pages) have comments or revision control enabled by default.
  • comments- By default the comment module is enabled in drupal. Here you can manage and moderate comments.
  • accounts- Create and modify users, user groups(in drupal it's called roles), and set role permissions. We'll visit this section shortly.
  • configuration- This is the most important part of the administration interface for the administrator. You control site-wide settings, themes, blocks, the installation and configuration of modules, as well as filters for submitted content. Get familiar with this section, folks.
  • taxonomy- Manage how content (even images) are categorized.
  • messages- Detailed site monitoring statistics. The initial admin screen is the brief version of what you see here.
  • help- Drupal documentation.

Setting Permissions

Drupal's default install is locked down pretty tight and nobody except the superuser has permission to view content. If that doesn't float yer boat, then let's take a look at changing it.

Navigate to administer » accounts » permissions. This page shows rows of permissions that each role can perform. By default there are two roles: anonymous user and authenticated user. The anonymous user is any user that visits your site and is not logged in or doesn't have an account. So with a clean drupal install, nobody can do 'nuthin except the superuser. The authenticated user role is the default role a user is assigned when after they create an account.

If you want a site that's open to the public, you'll want to check the access content permission under anonymous user. Most permissions can be divided up into two categories: access and administer. Access permissions control whether or not a role is allowed to view some form of content. Administer permissions generally control features such as modifying and configuring a feature. Be warned that some permissions are dependent on each other. For example, if you check 'administer site configuration' but not 'access administration pages', you'll never make it to the site configuration interface. Currently the only way to figure out these dependencies is through sheer determination and common sense.

A Crash Course in Module Management

You've probably already got a couple of modules you want to install or uninstall. To do that go to: administer » configuration » modules. If the 'status' column is checked, it means the module is installed. To disable it, uncheck the column. To enable a module, simply check the column.

What really happens when I enable a module?

Each module has the ability to build it's own configuration page. These pages live under administer » configuration » modules. Usually after you enable a module, this is the first place you want to look in order to tweak the new component.

A module also has the ability to add it's own permissions into drupal. For example, adding the path module will create two new permissions for you to manage.

Modules can also add new filters, blocks and even their own independent links. Sometimes after you install a module, you mat need to go to the help link and learn more about the newly enabled component.

Matt, respond to these questions:

I installed Drupal, but I would need some more detailled Tutorial, than the Documentation on this website. I could create some pages and they are visible in the main navigation block, but I don't know how to deal with Taxonomy, how to link the pages between each other...Is there a very basic Tutorial about using Drupal somewhere? Thank you very much!

I would also include a "usual suspects" sections for trouble shooting errors. Things to answer questions like "Why does it keep going back to the front page" and "I didn't change module X but now it suddenly stopped working."
c0c0c0 (aka "Dan")

From working with people, it is my experience that the first thing they want to do is (1) add some content (typically a static page) and (2) link to it from their main page.
Dries Buytaert ::

Jan 01 2001
Jan 01

The theming guide for Drupal 8 will get you started in the basics for theming a Drupal site. But, once you’ve learned the basics, what best practices should you be applying to Drupal 8 themes? There are lots of popular methods for writing and organizing CSS. The basics of CSS, of course, apply to Drupal.

  • Don’t get too specific
  • Place your CSS in the header and JavaScript in the footer
  • Organize your CSS well
  • Theme by patterns, don’t go top down
  • Preprocess your styles

Use configuration first

When it comes to Drupal, there are some common mistakes that happen when a front end developer doesn’t know Drupal. In general, apply your classes in configuration. Do not fill your Drupal theme with custom templates like you would for WordPress. Template files, especially with Twig, have their place. But, configuration should be your primary tool. My favoriate tool for applying classes is Display Suite and Block class. Panels is also good. And, fences isn’t terrible.

By applying your classes in configuration allows you to easily edit, reuse, and apply classes across every type of thing in Drupal. If you apply your classes with templates, it’s difficult to apply them across different types of content without cutting and pasting your code. However, don’t be afraid to use some presentational logic in your Twig templates.

Be careful what you target

In Drupal, there are many times where the only selector you have that will work is an ID. If you have this problem, Don’t use it! Never, ever, ever, apply your CSS with ids in Drupal. This is true for every framework, but in Drupal it’s a bigger problem because IDs are not reusable, they are hard to set, and they often change. A backend developer will not be able to apply your styles to other items without fixing your CSS for you. Don’t write CSS that you know a PHP programmer will have to rewrite because you don’t want your PHP programmer writing CSS.

Use view modes

Make sure to target your styles to reusable elements. So, avoid node types because those aren’t reusable on other nodes. Instead, use view modes and configuration to apply selectors as you need them.

Avoid machine names

This relates back to avoiding IDs. Machine names in Drupal sometimes need to change, and they are not reusable. So, don’t target them. Instead use view css, block class and configuration to apply classes to your content.

Don’t get too specific

Drupal 8 markup is better, but Drupal is still very verbose. Don’t get sucked in by Drupal’s divs. Only get as specific as you need to be. Don’t replicate Drupal’s HTML in your CSS.

Apply a grid to Drupal

Choose a grid system that allows you to apply the grid to any markup like Singularity or Neat. While you certainly can Bootstrap Drupal. Using Bootstrap on Drupal requires a heavy rewrite of the HTML which will break contributed modules like Drupal Commerce in obscure, hard to fix ways.

Use a breadcrumb module

Do not write advanced business logic into your theme templates. If your theme is programming complex features, move that code to a module. Or, install modules like Current Page Crumb, or Advanced Agg to handle more complex functions. This isn’t WordPress, your theme shouldn’t ship with a custom version of Panels.

Don’t hard code layouts

Use {{ content }} in your templates and let the View Modes, Display Suite, or Panels handle your layouts.

Don’t use template.php

If you need some ‘glue’, write or find a module meant for it. Drupal is built by many, many tiny modules. Learn to love it because well-written modules are reusable, maintained for free and always improving. Custom code dropped into your theme makes for hard to maintain code.

Jan 01 2001
Jan 01

Breadcrumbs are a pain point in Drupal 7. If you don’t know how breadcrumbs are supposed to work, go read this. The crumb should start with home and continue through to an unlinked crumb of the current page. Crumbs were implemented poorly, and breadcrumbs were difficult to modify in a module. Further, they were based on items in the menu. The breadcrumbs didn’t even allow you to edit the home title or include the current page title as an unlinked crumb. So, if you wanted breadcrumbs on a Drupal site, the first step was to choose 1 of 10 different modules to build them for you. Making matters worse, some themes decided to program breadcrumbs for you as well. If you’re stuck with a Drupal 7 breadcrumb problem, use a module I help maintain, Easy Breadcrumb. Trust me. I’ve got this for you.

Drupal 8 vastly improves breadcrumbs, but core still gets them wrong. They are based on the current page path exactly like Easy Breadcrumb in Drupal 7 which is a huge improvement. So, what did they get wrong? The current page title is missing. Bummer. So close. But, not hard to fix. So, lets do it! If someone tells you to program the breadcrumbs into your theme, don’t listen to them. They are doing it wrong. Themes should work with markup and presentation. They shouldn’t implement complex, reusable logic.

Drupal 8 has refactored breadcrumbs making them much easier for developers to extend or replace. This new architecture makes it easy for us to correct Drupal 8’s breadcrumbs. Unfortunately, the code from Larry’s post is a bit out of date and doesn’t work anymore. So, lets look at the code pulled from my module Current Page Crumb module that adds the current page title to the breadcrumb.

This code extends the PathBasedBreadcrumbBuilder core class to add the current page title to the breadcrumb. Since everything else needed for the breadcrumb is handled by the parent, line 31 does almost all the work for us. From there, we just need a few lines to add the current page’s title. If you’re looking for more examples to completely replace the core breadcrumbs with a custom builder, check out the Drupal 8 version of Easy Breadcrumb which does just that.

Jan 01 2001
Jan 01

Don’t store site configuration in the database during development because putting configuration in the database makes configuration difficult to track in version control. Instead, use the file system! Putting configuration in a database also makes it more difficult to restore, compare, sync, deploy, modify, and review the site config. Drupal 8 uses Yml files for configuration which are a perfect format for file-based configuration. In fact, this is the only method for storing configuration in BackdropCMS because BackdropCMS uses JSON files to store site configuration. Drupal uses Yaml to store your configuration the database, but storing Yaml in files was the default method for Drupal 8 when CMI was released. Many posts have been written about the default workflow for configuration. But, the promise of file-based workflow is more efficient.

Configuring in Files Workflow

When Drupal stores configuration files in the file system, all you do to save your work is run a git commit because as soon as you click save in a form, Drupal writes your changes to the configuration folder. Once your work is in code and committed to version control, you can publish those on GitHub and open a pull request to review your work before deploying it to production. This workflow is possible with database configuration, but it requires extra steps with Drush that can lead to errors and differences between environments.

Don’t Modify Production

No matter which storage you use for configuration, you should not edit your configuration in production. Instead, you should install the config readonly module in production and make all of your changes in your local environment. Clients who don’t install Drupal locally can make configuration changes in development. Using a host like Pantheon makes it easy to deploy files from development to production.

So Why Does Drupal Store Config in the DB?

I prefer keeping configuration in the file system, and BackdropCMS agrees with me. But, a few smart core developers don’t see it that way. So, why not? Drupal 8 is slow. And, some poor web hosts might allow the public to read configuration files.

Early in the release cycle the install process was slow. So initially, moving configuration into the database made running the installer a bit faster. However, file-based configuration in the current release of Drupal 8 doesn’t make the installer visibly slower. So, this isn’t a problem for our workflow.

The second concern with file based configuration is the desire for security through obscurity. Since we are storing configuration outside the webroot, and our web server should also be configured not to display configuration files, this isn’t an issue.

Another concern was that file configuration might encourage people to edit their configuration. Since this workflow is for programmers, this is an advantage of our workflow.

Advantages of Database Config Storage

Storing configuration in the database on production has some minor advantages. So, leaving the configuration in the database on production is reasonable. Storing in the file system means you have to sync the file system in multiple web server environments.

Storing config in the database allows you to attach metadata to the configuration so that you can timestamp it, assign an owner to it and create a revision workflow for configuration.

How to Enable Config in Files

The easiest way is to use the Drupal8-base installer which will enable file storage for configuration out of the box. Alternatively, you can export your site configuration from the database and then follow these quick steps to enable file-based configuration storage on an existing Drupal site.

Jan 01 2001
Jan 01

These core concepts apply to Drupal 8 site builds. However, many often apply to the other major web framework from WordPress to Node projects. Many of these ideas are documented on as well. I’m rewriting them here because I disagree with the documentation in several key areas.

Use The Same Development Environment

Everyone on your team should have exactly the same development environment. Using the same development environment ensures that the project runs exactly the same for each team member working on a project. You can do this with Vagrant, Ansible, or a Brew script.

Backups? Put The Database in Code With CMI

Configuration Management in Drupal 8 allows you to quickly store database settings in code. Further, content should come from a single reusable source. We use Google Docs API, others use Profiler. The key is keep your test content in a shared, predictable place. recommends that you backup your files and database. Since all of your code is on Github, and your database is in your code, Backups only matter in production. After a project launches, your hosting company should be providing backups. If your host isn’t taking care of this automatically for you, then switch to a web host like Pantheon, WP Engine, or Site Ground. All provide automated backups. Site Ground gives you per file recovery while Pantheon focuses on CMS backups for code/files/database in an easy to restore tool.

Never Hack Core (or Contrib)

Don’t change the framework. Instead, write your own code as a module. Pantheon, doesn’t follow this rule, and it creates a lot of extra work for them. But, they have an entire company of developers to maintain their fork of Drupal. The rest of us should stick to the official release. This is true no matter the framework you’re in. If you hack WordPress, your project will fail during automatic updates!

Use Test Sites

Your hosting company should be providing 2-3 sites for each production site automatically. If your hosting company doesn’t give you test sites, switch to Pantheon or WP Engine. You should make all your changes in your local environment first, test them locally, and then deploy them to test in production servers on a test server.

Use Configuration Before Code

Instead of hard coding a class or a snippet of logic into a theme, set these values in configuration and then apply the configuration with code. This allows your code to change in the future without being rewritten. This also leads us to choose high quality, well maintained modules to build our sites out of. Reusing code is one of the most basic steps in writing quality software because reusable code will have fewer bugs and more features.

Instead of writing a massive “glue” module, break up functionality into reusable modules and use configuration to apply advanced functionality so that each module is more powerful and easier to modify without rewriting the code.

Avoid Too Many (Poor) Modules

For those of us who work on large scale Drupal sites, we’ve learned that hundreds of modules can work together to produce an amazing, large-scale software project. When building enterprise Drupal sites, it’s more important to avoid using 1 poor module than it is to avoid 30 well built modules. This too many modules advice leads programmers to favor programming their own modules over reusing modules. However, avoiding contributed modules means you end up rewriting basic Drupal features in every new project.

This includes your custom modules only talks about contributed modules, but this too many modules advice holds for custom modules as well. The more custom modules you write, the more work it takes to maintain and modify your website. Instead of writing a large collection of custom modules, or a single giant glue module, consider publishing your modules on Github. This will encourage you to create reusable code that has configuration needed to make them reusable and future proof.

Follow Coding Standards

You can automatically check and repair your code for Drupal with Code Sniffer.

Up next, controversial configuration practices for Drupal 8 that will improve your workflow.

Jan 01 2001
Jan 01

I’ve taught an beginners course during Drupal Global Training Days many times in portland, and I give students an introduction to Drupal 8 for site builders. I spend the day simplifying Drupal for new developers. But once you’re beyond the basics of the interface, there are many different ways to accomplish a task in Drupal and Drupal 8 only adds to the choices. So, if you’re a Drupal developer looking to craft easier to maintain Drupal 8 sites, this series is for you.

Over the years I’ve developed many strong opinions about the best way to “drupal”. Some of my decisions aren’t actually better than alternatives, but they are patterns I’ve memorized to make my work more efficient so I can avoid getting stuck building sites. This series will cover the following topics:

And, if you don’t want to wait for me to write and publish all these best practices, feel free to join me in this Gist for a sneak preview without the explanations.

Jan 01 2001
Jan 01

Portland: A great place for designers and developers to join forces

Devsigner is celebrating the cross-overs, the multi-disciplinarians, the coders who paint and the designers who send pull requests — and those who want to develop some new left-right brain skills.

We’re looking for folks to break out of their familiar meetup silos and apply their knowledge across the crafts of development and design.

Join me at Devsigner in Portland, Oregon, May 23-25!

Tickets are now on sale, and session submissions are open until this Friday, May 2!Devsigner: Portland, OR, May 23-25

Sessions will include things like:

  • responsive web development for graphic designers
  • color theory for coders
  • industrial design for web apps
  • why bad user experience is a bug
  • what web technologies can learn from analog design
  • iterative design in open-source communities
  • your great idea — submit a session now!

We’re going to mix it up with a variety of session formats:

  • Traditional presentations (45-60 minutes)
  • Panel and roundtable discussions (45-60 minutes)
  • Hands-on, deep-dive workshops (2 hours Friday, 3 hours Saturday and Sunday)
  • Lightning talks on Saturday night (more information to come)

We’re also kicking off the event with a keynote presentation from a surprise guest!

Who should attend?

  • graphic designers who want to hone their web design chops
  • developers who want to the beauty of their projects to match the beauty of their code
  • artists who are tired of ugly or unusable websites
  • branding experts who want to tell developers a story about the cobbler’s children
  • Sass/Puppet/Angular/Grunt/Node evangelists who want to spread the good word
  • you!

I hope to see you there!

Thanks to RootWork for the post.

Jan 01 2001
Jan 01

Steve Sounder’s is an authority on web performance. He writes about everything from front end performance to browser performance. As a front end developer, it’s easy to get lost in tasks that don’t matter. There’s a saying in software development, “Don’t optimize until you need to.” In frontend development, that doesn’t apply because we don’t write complex algorithims. But, it’s important to make sure we focus our time and attention on the right stuff. So, what is the right stuff.

The best practices to focus on as a front end developer are the ones that have the most impact on site performance and user preception. To that end, here’s 4 topics that you should put special effort into:

  • Prevent jerky, flashy page loads. Restyling content after page loads is annoying and interrupts reading content.
  • Javascript, CSS and images should be minimised and compressed.
  • Images should be responsive and only as large as they need to be.
  • JavaScript and third party content should only load as needed and shouldn’t cause your site to fail or delay.

CSS at the Top

Load CSS at the top of head and JavaScript at the bottom of body. Putting all your CSS in a file at the top of the document prevents any unstyled elements from loading. Avoid inline CSS and printing CSS in JavaScript. Lastly, put your JavaScript in the footer so visitors can read the content of your website while your scripts are loading. If you can’t put your animations in the footer, use a loading graphic.

Prevent Flash of Unstyled Text

Preventing FOUT is a quick and easy win. Firefox and Internet Explorer both do a terrible job loading @font tags. These browsers cause the original unstyled text to flash, sometimes for a couple of seconds before the page is redrawn. This affect can even break your layouts on a page that uses thin custom fonts. All that’s needed is adding a bit of JavaScript when you include custom fonts:

<script src=""></script>
google: {
families: ['Droid Sans', 'Droid Serif']

Grunt to Compress, Minify and Optimize

Grunt automates your workflow so that you never forget to put your SASS into production mode again. It allows to string together tools so you can combine, minify, and compress your static files, and optimize your images. You just type Grunt build and Grunt works it’s magic. These tools can easily save you 500KB on a large project.

Responsive Images Done Well

If you’re loading a 1400 pixel hero image on a 320 pixel smart phone, your page load is going to suck. Instead, use tools like Borealis or Picture to load the best size image for the visitor. Converting a slide show to responsive images can easily save 400KB. That’s a huge win.

Prevent Single Point of Failure

Modern websites almost always include JavaScript from Facebook, Twitter, Google, LinkedIn, AddThis, Discuss and other sources. If done incorrectly, these third party scripts can each cause your page to white screen. To avoid this is simple. You should always use asynchronous snippets. If you don’t have an Async snippet, then place the JavaScript just above the footer.

CDN Saves the Day

If you use Cloud Flare as a free content delivery network, Cloud Flare will compress and minify all your code and html. It will combine all your CSS and JavaScript and it will asynchronously load all of your JavaScript. All you have to do is set up Cloud Flare which takes only a few minutes. When you do switch to CF, you’ll want to exclude your web font loader and any other critical javascript from the “Rocket Loader” so it doesn’t get loaded last.

So, load your fonts well, clean up your code, correctly load images, and move all your JavaScript to the footer, or just use Cloud Flare and forget about performance.

Jan 01 2001
Jan 01

Using AJAX to update a Drupal 7 form could be easier. The documentation on this feature is extremely verbose, and I had a difficult time piecing together a working example. So, here’s the code to modify the values of a second field when the value of the first is selected. The code below will use the taxonomy_voc drop down to control the product model drop down values. This code does not work with field widgets that define their own AJAX.

Wrap the field that’s being controlled and add the callback and wrapper to the controller field.

Thanks to Anne Sturdivant for her assistance in writing this code.

 *  Implements of hook_form_alter() to update a field via AJAX.

function hitachi_module_form_alter(&$form, &$form_state, $form_id) {
  switch ($form_id) {
    case 'contact_us_entityform_edit_form':

    // Wrap the field that being controlled
    // Add the callback and wrapper to the controller field

    // Create a wrapper for the AJAX callback to populate the model
    $form['field_product_model']['#prefix'] = '<div id="hitachi_wrapper_type">';
    $form['field_product_model']['#suffix'] = '</div>';

    // If we are editing an existing form, we already have the values
    if (!empty($form['taxonomy_voc'][LANGUAGE_NONE]['#default_value']) 
        || isset($form_state['values']['taxonomy_voc'][LANGUAGE_NONE][0])) {
      $form['field_product_model'] = _hitachi_set_model($form, $form_state);

    // Create an AJAX callback. This is the magic bit that does all the AJAX.
    $form['taxonomy_voc'][LANGUAGE_NONE]['#ajax'] = array(
      'callback' => '_hitachi_set_model', //Must match the function name below
      'wrapper' => 'hitachi_wrapper_type',

 * AJAX callback to grab all the nodes with a given term.
function _hitachi_set_model($form, $form_state) {
  if (!isset($form['#after_build_done']) && isset($form_state['triggering_element'])) {
    $product_types = array_keys($form_state['triggering_element']['#value']);

    // Populate all the product models with all the product titles from that division.
    foreach($product_types as $product_type) {
      $entities = _hitachi_module_get_nodes_from_tid($product_type);
      $nodes = node_load_multiple(array_keys($entities['node']));
      foreach($nodes as $node) {
        $title = entity_metadata_wrapper('node', $node)->title->value();
        $key = preg_replace('/[^a-z]/i','', strtolower($title));
        $form['field_product_model'][LANGUAGE_NONE]['#options'][$key] = $title;

  return $form['field_product_model'];

Jan 01 2001
Jan 01

So, I’d like to stop using waterfall development for Drupal projects. The first step is to teach myself to be a good advocate for something different… Started way back in the early 90′s was a thing called scrum… It really is very different. Here are some resources that don’t suck.

Not all positive:

It’s funny, when I got a computer information systems degree, we all laughed about waterfall development. But, client’s demand fixed bids! Can you be agile with a fixed scope, budget, and timeline?

Jan 01 2001
Jan 01


grep 'DocumentRoot' /etc/httpd/vhost.d/* | awk {'print $2;'} | xargs -I {} nice find {} -name CHANGELOG.txt > ~/drupal-sites.txt

Produce clean report:

cat ~/drupal-sites.txt | xargs head -n 3 > ~/drupal-sites2.txt


grep 'DocumentRoot' /etc/httpd/vhost.d/* | awk {'print $2;'} | xargs -I {} nice find {} -name readme.html > ~/wp-sites.txt

Todo: Add string to pull WordPress version with pretty formatting.


nice find -L /vol/www/ -name 'PKG-INFO' | xargs grep '^Version:' > ~/django-sites.txt

Jan 01 2001
Jan 01

I’m in the process of migrating an old PHP website for Portland State University from a custom database into Drupal 7. Doing the data entry on hundreds of nodes with multiple custom fields, taxonomies, and images would have taken ages. So, instead I imported the data into Drupal with a PHP script. At first, I attempted to use phpMyAdmin, to export a CSV, and then import the CSV using the Feeds module. However, the feeds module for Drupal 7 doesn’t seem to do field matching well, and I couldn’t get the taxonomies or images to import correctly. So, with the help of my intelligent coworker, I decided to use Drush to execute a PHP script that will import the content. The process wasn’t hard for a PHP programmer, but all the directions I found on other blogs were either confusing me, or missing a few steps. Mainly the examples were missing the code to insert dynamic data from a database in a loop.

This being my first Drupal 7 project, I had a lot to learn about new Drupal features. Don’t worry, I’ve attached the code, so you can cut and paste my hard work.

Import content into Drupal 7

  1. Create the taxonomies and terms that you will need. This can be done with a script, but most websites don’t have that many categories.
  2. Create a content type for the nodes and include all the custom fields you will need. Be sure to include term reference fields for each taxonomy from step 1.
  3. Install Drush and get “Drush help” to work.
  4. Create a PHP script, and execute it with drush php-script (script name)

Drush is nifty because it loads the Drupal environment and allows you to access Drupal’s functions. This saves you from having to figure out where to insert all the node data manually.

Connect to the database and get content

// My source data was not normalized. All data was in 1 table! Lucky me. No joins.

$query = 'SELECT * FROM `tb|record`';
$result = db_query($query);
$i = 20;
foreach ($result as $row) {

Most of what Tim wrote worked perfectly, but here’s what Tim has to say about assigning content to categories…

Add a term to a node

$node-&gt;field_tags[$node-&gt;language][]['tid'] = 1;
‘field_tags’ here is the name of a term reference field attached to your content type, ‘1′ is a term id you wish to assign to a node. Simple!

Now here’s the code I actually used to insert my content into a category. It wasn’t simple:

 if ( $term = taxonomy_get_term_by_name($row-&gt;culture) ) {
$terms_array = array_keys($term);
$node-&gt;field_culture[$node-&gt;language][]['tid'] = $terms_array['0'];

If you review my code, you’ll notice that I failed to get my loop to read and load the taxonomies from the database, so I added them one a time. If anyone can figure out the syntax error in the block of code that’s commented out, that would be awesome. Contact me, and I’ll give you credit. But, I doubt many sites have more than a handful of categories.

The script took me about 10 hours to perfect after I threw away 2-3 different methods. Hopefully, you can copy this script and get your site converted over to Drupal in much less time.

The Full Source Code

<!--?php <br ?--> cm_load_rep_data();

function cm_load_rep_data( ) {

// My source data was not normalized. All data was in 1 table! Lucky me. No joins.
$query = ‘SELECT * FROM `tb|record`’;
$result = dbquery($query);
$i = 20;
foreach ($result as $row) {
$node = new stdClass(); // We create a new node object
$node->type = ‘piece’; // Or any other content type you want
$node->title = $row->subject;
$node->language = LANGUAGE_NONE; // Or any language code if Locale module is enabled. More on this below *
$node->uid = $i; // Or any id you wish
$url = str_replace(” “,””,$row->subject);
$node->path = array(‘alias’ => $url) ; // Setting a node path
node_object_prepare($node); // Set some default values.

//grab the file for this node based on the “schema” from the old website…
$file_path = ‘/home/gboggs/Images_data/’
. $row->collection_alias . ‘/’
. $row->collection_alias . $row->accession_no . ‘.jpg’;

if (file_exists($file_path)) {
$file = (object) array(
‘uid’ => $i ,
‘uri’ => $file_path,
‘filemime’ => file_get_mimetype($filepath),
‘status’ => 1,
$file = file_copy($file, “public://”);
$node->field_image[LANGUAGE_NONE][0] = (array)$file;

// Grab the body content. My database had the body content repeated. You don’t need this piece.
if (!isset($row->long_des) || $row->long_des == null) {
$body = $row->short_des;
} else {
$body = $row->long_des;

// Insert the content into the node
$node->body[$node->language][0][‘value’] = $body;
$node->body[$node->language][0][‘format’] = ‘full_html’;

// Let’s add some CCK fields. This is pretty similar to the body example
$node->field_collection_number[$node->language][0][‘value’] = $row->accession_no;
$node->field_dimensions[$node->language][0][‘value’] = $row->dimension;
$node->field_date[$node->language][0][‘value’] = $row->date;
$node->field_artist_author[$node->language][0][‘value’] = $row->artist;
$node->field_provenance[$node->language][0][‘value’] = $row->provenance_prior_pub;
$node->field_details[$node->language][0][‘value’] = $row->object_details;

/* This doesn’t execute, and I couldn’t figure out why in < 10 minutes. so doing it the long way.
$categories = array(‘field_culture’ => ‘culture’,
‘field_medium’ => ‘medium’,
‘field_time_period’ => ‘time_periods’,
‘field_collection’ => ‘collection’,
‘field_theme’ => ‘theme’);
foreach ($categories as $field => $category) {
$term = taxonomy_get_term_by_name($row->$category);
$node->$field[$node->language][][‘tid’] = $term->tid;

// The long way to check taxonmy terms and add them to the node.
if ( $term = taxonomy_get_term_by_name($row->culture) ) {
$terms_array = array_keys($term);
$node->field_culture[$node->language][][‘tid’] = $terms_array[‘0’];

if ( $term = taxonomy_get_term_by_name($row->medium) ) {
$terms_array = array_keys($term);
$node->field_medium[$node->language][][‘tid’] = $terms_array[‘0’];

if ( $term = taxonomy_get_term_by_name($row->time_periods) ) {
$terms_array = array_keys($term);
$node->field_time_period[$node->language][][‘tid’] = $terms_array[‘0’];

if ( $term = taxonomy_get_term_by_name($row->collection) ) {
$terms_array = array_keys($term);
$node->field_collection[$node->language][][‘tid’] = $terms_array[‘0’];

if ( $term = taxonomy_get_term_by_name($row->theme) ){
$terms_array = array_keys($term);
$node->field_theme[$node->language][][‘tid’] = $terms_array[‘0’];

$node = node_submit($node); // Prepare node for a submit
node_save($node); // After this call we’ll get a nid

// printing from Drush is easy
drush_print( $row->subject . ” added.\n” );

Jan 01 2001
Jan 01

Internet Explorer is often the bane of a web designer’s existence. Creating a design in Firefox or Chrome is easy, if something is off, click “inspect element” and you can fix the problem inminutes. However, in Internet Explorer, there’s no such tool. Well, I had an issue with JQuery not displaying correctly on a Drupal site in IE7. It worked perfect in 8, Firefox, and Chrome. The demos for all the plugins I was using worked perfectly in Internet Explorer 7, but when I loaded them on the Drupal site, they were hosed. I checked the code over, and over, and over again. I have my reservations about Drupal. I hate how it creates so many external files, and how many “Gotchas” it has. I knew this had to be one of those weird Drupal quarks.

Optimize CSS Files

After hours of frustration trying to get JavaScript to run, I opened the CSS file for IE in Drupal:

  • CSS targeted specifically for Internet Explorer for Windows.
  • Any CSS in this file will apply to all versions of IE. You can target
  • specific versions of IE by using conditional comments. See your sub-theme’s
  • .info file for an easy way to use them.
  • While building your theme, you should be aware that IE limits Drupal to 31
  • stylesheets total. The work-around for the bug is to enable CSS aggregation
  • under: admin / settings / performance.

I turned CSS caching on and all my JQuery started working perfectly! I had overrun the limit for maximum allowed external files in IE7! How can Drupal possibly include more than 31 external files? Man, Drupal is insane. It’s loading 2 files for every plugin I need. Anyway. Mystery solved. If you can’t get JQuery, or CSS to work in Drupal on IE7, optimize your CSS files and see if that fixes all your problems.

Jan 01 2001
Jan 01

Drupal sites often suffer from a less than ideal editor experience. While Drupal 8 improves on the default experience by providing inline editting, working preview, and moving the ‘advanced’ options to the sidebar, there’s still common mistakes that will lead to poor a experience. As a part of my on-going Drupal 8 Best Practices series, lets look at what we can do to build good admin interfaces.

Here are a few major principles behind the admin experience:

  • Use as few content types as reasonable.
  • Use permissions to hide unneeded options.
  • Content should not be defined in code.
  • Content and layouts should be editable by the editor without modifying code or css.
  • Content should have a contextual edit link.
  • A site should not require admin access to figure out how to edit.
  • Content should be stored in nodes, not entities or taxonomy terms.
  • Taxonomy can be used to apply additional page styles.
  • Taxonomy terms should have limited fields.
  • Vocabularies shouldn’t be too large or too deep.
  • The editor should have easy links and dashboard.
  • Editors should be given the Clear Cache permission.
  • CKeditor should be configured to allow pre-selected CSS styles.
  • Editors should have a simple tool for applying layouts to new pages.
  • Editors should be able to apply custom CSS via a drop down.

Give Permissions Carefully

Clients should be given the admin password for user 1, but every user should log into the site with their own user account that has an ‘editor’ permission set. This editor account should only be given permission to do the things they do frequently.

Content Should be Editable

There’s no reason to hard-code content into your theme or PHP. Every piece of text on the page should be editable through the hover edit link over that content. If you can’t edit something without a git push, then it should be a blocking bug.

Content Should be Stored in Nodes

This is a common mistake. Taxonomy terms are not content. They are meant to organize content. So, if you’re putting fields (especially text fields) on terms, you’re prboably making a pretty big error because taxonomy terms can’t be unpublished, promoted, or revisioned easily. If you’re putting content into custom entities, you’re probably also making a mistake because entities take a lot of extra work to get the basics that you get from nodes for free.

Think of WordPress here, do you see your user profile when you first log in? No, you see a dashboard of content to edit and other useful information. Do the same in Drupal, redirect login to admin/content if nothing else. Give folks short cut links in their menu bar as well.

Did You Clear the Cache?

Lets face it, the cache clear problem from Drupal 7 is a bit worse in Drupal 8. There are many times you need to Cache Rebuild. So, give them the button.

Use a Layout System or Layout Taxonomy

Panels and Display Suite are popular because they are powerful, stable, uesful and easier to use than default Drupal. No matter what tools you use, give your editors easy abilitiy to apply a layout to a new page. Don’t hand code each page. Build layouts, and apply them. Even a simple ‘Layout’ taxonomy field can allow editors to apply layouts to content.

When deciding how to build things in Drupal 8, always spend some thought on how to make sure each piece of content will editted. Not only will your customers thank you, you’ll be making Drupal look good.

Jan 01 2001
Jan 01

Have you ever had a client ask for everything to be red? Or perhaps it was auto playing audio on every page load? Well, check these awesome sites out.

Portland is a Drupal epicenter. The Drupal community comes together strongly in many places around the world and Portland’s Drupal User Group is no exception. Once a month we gather for conference quality presentations about all sorts of advanced Drupal topics. Last night our fantastic host, Jason, Yee (JYee) did something different. He had us break into 7 teams with the goal of using 4 specific modules to produce a website that’s awesome in 1 hour. The competition was stiff. Everything from advanced working, feature-complete Drupal builds to sparkles that actually sparkled. I appologize now if any of these screen shots make your eyes water.

Tweet with us at #pdxdug.

We ended up learning a lot about Flags and Rules. I had the luck and privlege of project managing a 1 hour project for an amazing Drupal team:

@illepic – Chris Bloom, Drupalist at Superstar Media
@mpgeek – Eric Paul, Drupal developer at Open Sourcery.
@mikey_p – Michael Prasuhn, 1⁄2 of Shomeya

The Awesome Websites


modules: bad judgement, fivestar, userpoints
alt/bonus module: webform


modules: nodequeue, privatemessage, viewfield (or eva)
alt/bonus module: webform


modules: field collection, flag, userpoints
alt/bonus module: views_field_view


modules: better exposed filters, fivestar, rules
alt/bonus module: webform


modules: bad judgement, flag, message
alt/bonus module: userpoints


modules: field collection, message, privatemessage
alt/bonus module: rules


modules: field collection, message, nodequeue
alt/bonus module: privatemessage

Special thanks to O’Rielly,, and Lullabot for sponsorship that included beer, pizza, coffee cards and an OScon pass! My group ended up winning, but all the sites are awesome. So, I’ll leave it up to you to guess which one was ours.


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