Upgrade Your Drupal Skills

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

See Advanced Courses NAH, I know Enough
Jan 02 2011
Jan 02

Thanks to everyone who read the posts in my $100 Drupal site series. Today I will be responding to some of the points people have raised in comments and via email as well as adding a few closing comments.

Undervaluing Labour

Some have suggested that the only way to make a venture like this work is to work for a few dollars an hour. I completely disagree with that! If you are building every project from scratch and only charging your clients 100USD, you will be working for peanuts, but I’m not advocating that model. I’m encouraging people to rethink how they manage their development workflow. Although there are initial costs in learning new tools, over time you will end up spending less time on site builds and so increase your profits.

$100 is too Cheap

I agree that 100USD is very cheap for a high quality Drupal site and in most western markets it is probably too cheap. Sure you can do it and make the profit on the margin, but you have to sell a lot of sites to recover your initial investment. The “$100 Website” can be a useful sales pitch. Don’t charge 100USD per site if the market will happily pay 5 or 10 times that. It doesn’t matter if you are charging 10USD per site or 250kUSD per site, the same basic rules apply - understand your client’s requirements and know the market.

There is a growing list of freemium services out there too, including Drupal Gardens and WordPress.com. Depending on your business model you may want to have a basic freemium offering.

What Does the Competition Offer?

Investigate what the competition is offering. There is a large market for hosted CMSes these days, go see what some of them are doing. What do you think they are doing right? What do you think they lack or could do better? A quick list of services I’d recommend you check out are (in alphabetical order):

I’d recommend spending some time searching for hosted CMS solutions. Sign up for the free or trial services and see what they’re like.

Do I Need a Lot of Money to Do This?

Although in the Resources and Infrastructure post I outlined the positions I thought your team needed to make this happen, it wasn’t a list of must haves. You need to figure out what works with you. It would be possible for a couple of switched on people to do this as a basement startup, so long as you have the skills and connections to get everything you need in place. If you can only drive a server using cPanel, then you need to find a sysadmin. If you can’t even draw stick figures, then you will need to hire a designer. Your staffing costs are really going to dictate how much money you will need to get this up off the ground.

Why Did You Do This?

I wanted to put the idea out there. I wanted to see how people would react. It wasn’t that long ago that people could build a profitable business selling websites built using Dreamweaver, and some people still do, but the market is changing, so too is the Drupal market.

For some time I have been thinking about how you’d develop a low cost Drupal based hosted CMS solution. There are 2 main reasons why I haven’t just gone and built it already. The primary reason is I hate being on call and running a hosting service such as this requires me to never be out of range of a 3G tower for more than 30 minutes, customers won’t accept that the server crashed 15 minutes after I hoped on a flight to the US or Europe. Secondly building such a solution takes time and I have a family to feed, I don’t think my landlord would cop me not paying the rent until this thing started to turn a buck.

I have very consciously put enough information into this series to allow someone to head off in the right direction. At the same time I’ve held back on some of my execution specifics, because if I was to go build something like this I want to have some things which make my service unique.

I was hoping to present a session at DrupalCon Chicago on this topic, but I found out yesterday that my proposal hasn’t been accepted. As I understand it, there will be a small number of sessions announced sometime in the next 2 weeks, but I’m not holding out much hope of being selected then. There is always London.

Can You Build This for Me? / I Need Help!

If you are serious about building a service like this or using some of the tools I’ve discussed, I’d be happy to talk to you. I have about a decade’s worth of experience running my own business and developing web apps. I have offered training and consulting around many of the topics I have discussed in this series.

So neither of us waste our time, I will be up front about how I see things working on my end. I expect to be paid for my time, I’m happy to take some equity, but I’ve got bills to pay. I have put a lot of thought and energy into this, so I am very unlikely to sign a contract which gives you ownership of my IP. If you can live with the above, then please contact me.

It Didn’t Work for Me

Sorry that just the way things go in business sometimes. Not everything I’ve tried over the years has worked either. Learn from the failure and try again, maybe doing something completely different.

Disclaimer: Don’t sue me if this doesn’t work out, do your own research and seek professional advice before acting on anything on this site.

Will you Write More on these Topics?

Maybe. I will probably turn some of the content from Horizontally Scaling Drupal workshops and talks into blog posts, and possibly a book. I tend to blog when I feel passionate about something. Subscribe to my RSS feed, or follow me on twitter to find out what I’m working on.

In the mean time, I’d recommend you subscribe to the following blogs / follow these people on twitter:

I welcome comments, feel free to leave one below.

Dec 30 2010
Dec 30
How to add a block region to a node page in Drupal 6 » Danny Englander

Drupal engineer with a passion for learning new things every day

As a Drupal themers / front end developers, we are always asked to push the envelope of what's possible with design and theming. With Drupal 6, custom block regions are usually added in page.tpl.php which is normally outside of the actual page node content / comments. It would be above, below content or in sidebars typically. Occasionally you have the need to add a block region within a node area. This comes in handy especially if you are using a custom themed node page that uses CCK fields, e.g., "node-[custom_content_type].tpl.php".  To accomplish this there are a few steps involved.

How to add a block region to a node page in Drupal 6

  1. Determine and add code to the node type you will add it to in your theme. It might be simply node.tpl.php or a custom named node as mentioned above.
  2. Add a preproccess node function to your theme's template.php
  3. Add the new region your theme's .info file
  4. Flush your site cache
  5. Test it out either using context or the actual block page assigning an existing or new block to the new block region

First we need to determine the name of the new block region that we are going to add. In this tutorial we will call it "node_message". In the node page you want to add code to determine where in the page you want to add it. This part is just like adding a regular block region to page.tpl.php. In our example node.tpl.PHP, we will add the new code after the $content and post meta variables. Note that your node or custom node template file may vary but this will give you an idea of what's possible. Here is code near the bottom of node.tpl.php.

   print $content ?>
if ($links): ?> class="postmeta"> print $links; ?> endif; ?>

We now insert our new "node_message" block code at the end. Note that you could also wrap a custom div class for the new code as well as illustrated in our example. This new block region should not already be in page.tpl.php as you do not want the region to load and process twice so it should be unique to the node.tpl.php level.

     print $content ?>

 if ($links): ?>
     class="postmeta"> print $links; ?>
   endif; ?>

  if ($node_message): ?>
      class="node-message"> print $node_message; ?>
 endif; ?>

Now we need to tell Drupal how to process this new code so we will go ahead and add our preprocess function to our theme's template.php file. Note if your theme does not have this file you can go ahead and create it. If it is a new template file with nothing else added you need to add an opening tag but not a closing one. If you are adding to an existing template.php file with existing code, then it's not necessary to add the opening tag.

function my_theme_name_preprocess_node(&$vars, $hook) {
  $vars['node_message'] = theme('blocks', 'node_message');

Note above that "my_theme_name" should be the actual name of your theme so you will need to replace that as well as 'node_message' which is the custom name of your block if you decide to change the name.

The next part entails adding the new block region to your theme's .info file. You can do something like this:

regions[node_message] = Node Message

Again take care in the name, it must reflect the actual name of your block, i.e. 'node_message'. Now we are at a point where you can go ahead and clear your site cache and assign or create a new block on the /admin/build/block page. The new custom 'node_message' region should show up on in the regions drop down menu on this page. If you have Drupal's Context module installed, you can also assign your block to the newly created region using that.


An interesting conversation transpired on Twitter after I posted a link to this blog post: Twitter Conversation

Amy Stephen (@AmyStephen) suggested that this tutorial was similar to using {loadmodules positionname} in Joomla & Steve Burge (@alledia) suggested you could use the Drupal module, Insert Block. This method while similar is more of a one off type implementation for single pages.

What this tutorial does is show you programmatically how to add a block within a node that can be leveraged globally. In a way the Insert Block module is more granular where you can literally insert a block between two paragraphs. The method described in this blog post would be ideal for example of having a block on 50 different pages between two specific CCK fields in a custom themed node which you could simply set with one Context instance.

In the screen capture below you can click to enlarge and see an example of a custom block added within a node. I hope this tutorial has been helpful, feel free to comment with any feedback or issues. This tutorial was inspired by a post on drupal.org: http://drupal.org/node/361209


Dec 29 2010
Dec 29

During this series on creating a profitable business around the concept of building Drupal sites for $100 I have attempted to demonstrate that there is a viable business model here. I don’t believe it is a business that will suit everyone and nor do I believe every developer will want to work on such a project, but for some this will be an excellent opportunity. Today I will cover some of the things that I think you should consider before investing too much in this business model. Some of this is just basic business sense which isn’t specific to this project.

Dollars and Sense

Oscar Wilde once wrote “What is a cynic? A man who knows the price of everything and the value of nothing”. If you want to build this type of business, be frugal, but not a Scrooge. Generally a good developer will cost you more in salary than an average one, but the good developer will work out cheaper in the longer term. A similar thing goes for hosting, avoid Virtuozzo based VPS and look for someone offering the more expensive Xen or KVM based platforms, they are less likely to oversell capacity. At the same time keep an eye on the markets you are buying services in to ensure you are always getting the best value for money.

Recognise when you have to pay for something. Spending a little now might save you a lot in the long run.

In House vs Outsourcing

It makes sense to outsource some services, for example email. You want to focus on offering a high quality Drupal driven SaaS, having to support email too is a lot of hassle, use Google Apps for Domains or similar service.

Some things are better performed in house, such as design and themeing. There are businesses around who offer cheap PSD to Drupal theme conversion services, but these services usually cut corners which will cost you more in the longer term. Having someone in house means that they can learn from others on your team and do things the right way for your business.


Although the theme of this series is “$100 Drupal site”, that doesn’t mean every site you sell should be $100. You need to research your target market/s and make sure you are pricing your product/s appropriately. I would seriously consider offering 3 levels of service, each level should offer more options, bandwidth and storage. Some customers will be drawn by the initial $100 price tag, but when they see the feature list, the $250 product might be more appealing. Give customers a sense of choice.

Options and Up Selling

Find opportunities to sell extras to your clients. Not everything needs to be included in the base level package. I discussed enhanced support offering in my previous post, which could provide additional revenue.

Most of the clients who sign up for this service will have no interest in paying for a custom theme and/or development, but once you have them through the door you have more chance of selling such extras to them. Find the higher traffic clients and connect with them, see if they want more. The price jump is likely to be significant, but if they can see value in it, they may pay for it.

Domain Names

Domain names is a great opportunity to generate extra revenue. By default customers should get biz-name.example.net, and charge them a fee if they want to use another domain, such as mybiz.com. Most people know that GoDaddy sells domains for around 10USD, while Melbourne IT charge around 75USD. Sign up for a reseller account with one of various domain registrars and offer customers domains directly from your service. If a customer brings their own domain charge them a fee, if they buy the domain through you advertise that you waive the setup fee, but then include it in the pricing of the domain name.


Seek out partners. If you can find a company which offers a service which is a good fit with your business, work out a deal with them. Be it bulk licensing, reseller, commissions, find something that works for both parties. Your customers can benefit from such arrangements too.

Giving Back

Previously I mentioned that you will be benefiting from the great work of the Drupal community, you should acknowledge this benefit by contributing back to the community where it is appropriate. Not only does this help build the profile of your business in the community, it can reduce your maintenance workload. For example if you have a patch which fixes a bug or adds generically useful functionality to a module, push it back up stream, so you don’t have to maintain the patch. Consider having a budget for sponsoring community events to help build good will.

Data Exports

Allow customers to export their site and go host it with someone else. This might sound counter intuitive, but if they are just a base package customer and you are hosting them, they have paid you. If they are only 2 months into 12 month service, which should be non refundable, then let them take their site, that frees up server resources. It is also the ethical thing to do, don’t make your money because people are locked into your service, they will eventually resent you for it.


Drupal itself is licensed under the terms of the GPLv2 (or later) with some contrib modules depending on GPL compatible code. If you are contributing code back to drupal.org it must be under the terms of the GPLv2. You could choose to offer the non PHP parts of your code under CC-BY with an attribution in the footer, you could release your features under the terms of the AGPLv3. These are business decisions you must make in the context of the rest of your business.

Pay for Expert Advice

There are times when you need an expert. Get a lawyer to check your Terms of Service and any significant contracts. Use an accountant to get your financial affairs right from the start. If your servers are performing poorly and your Sys Admin can’t work it out, pay for someone who can. Sometimes it is better to pay for something than trying to learn how to do it yourself.


Blog about your experiences, share the knowledge. I’m not advocating putting your entire business plan online, but discuss problems you’ve solved, code you’ve created so others can benefit from your experiences. Don’t be afraid to share, Scott Adams sums this up perfectly “Ideas are worthless. Execution is everything”. I have nothing to fear in publishing this blog series, after all it is just my ideas.

What’s Next?

This is the last substantial post in this series. I have tried to break it up into digestible chunks. Thanks for taking the time to read my posts and I welcome any comments you may have.

I plan to let things sit for a few days. Over the weekend I plan to review the comments posted and emails received as part of preparing a summary response and conclusion. Anything else I think of will get tacked onto that post.

Dec 28 2010
Dec 28

Through out this series, the cost of labour has been identified as one of the biggest risks for this project. As most people who have run a tech business know, support can turn into a massive black hole of wasted time. Today we will look at how to manage support in a way that helps you avoid any direct customer contact for support.

Documentation and Online Resources

People like documentation, or even better videos, to walk them through a process. Invest the time up front to create documentation to help your customers use your platform. Only offer a single admin theme, such as Root Candy or Rubik or something you create yourself, this way the UI remains consistent and users are less likely to get confused. When developing the documentation, assume the user has no Drupal experience and talk in generic lay person terms, not “Drupal babble”. You should include links in the Drupal interface back to your help system, so people can access contextually appropriate help. Consider having a FAQ for each discrete piece of functionality so people can get some idea of what it does without having to play with it for half an hour.

A lot of the documentation you generate will be specific to your business and only available to your paying customers, but some of it will have generic value to the Drupal community. For the more generally useful content, publish it in a public place, such as your blog, company website or contribute it to the appropriate section of the documentation on drupal.org. You will be benefiting greatly from the work of the Drupal community, you should be looking for opportunities to give something back.

The flexibility of Drupal means that you should be able to build a documentation system that suits your needs. You probably want to start by extending the book module.


From time to time people won’t be able to find what they need using your online documentation. If you have a solid user base, a forum can be a good way of crowd sourcing your support resources. This doesn’t mean you can just put up a forum and hope that your users will all help each other solve their problems, you need to be in there responding in a timely manner too. If you have some users who are contributing regularly in the forums, acknowledge that in their profile and even offer them some free time on the service - after all they’re saving you money.

Support Tickets

Some users will want a more personalised approach to support. This will most likely involve email. When a user emails support directly, they will expect a timely response. This has the potential to add significant costs to your business, especially if you have a global customer base. One way to deal with this additional cost is to charge for it, offer packages of X incidents per month for Y dollars and put them on recurring billing. Most customers will forget to remove the recurring billing, but stop asking questions once they are up and running. There are various support systems available, I’ll leave you to find the one which works best for you.

Chat and Telephone Support

Real time support channels such as chat or telephone can really eat into your bottom line. You need to have people sitting there waiting to take the “call”, whatever time the customer contacts you and they may not call for a day. Accents and cultural issues can make it difficult to communicate effectively via the telephone. I would avoid offering any telephone support to customers.

Mailing Lists

A mailing list can be an effective way of communicating with your users. I’m not suggesting something like MailMan or Google Groups, I am talking about a one way announcement list. Check out MailChimp or Campaign Monitor to take care of this for you. Each month send out a newsletter with some useful tips, new features or announce other improvements to the service. Consider including case studies in the newsletter, which you can also feature on your sales site.

Customer Service

The cheapest way to build a business is through referrals or word of mouth. You need to look after your customers, so they become your sales team. Manage their expectations in terms of the support you offer them. Don’t be afraid to cut a time sink loose, apologise, give them a refund and encourage them to find another solution. Support vampires can cost you a lot more than they’re worth.

What’s Next?

We are almost in the home stretch now. In the next post I will cover some of the business considerations in terms of what you offer to customer and how to upsell. The final post in the series will come later this week and will be a summary of the previous posts.

Dec 28 2010
Dec 28

So far in this series we have covered a potential target market and business plan, resources and infrastructure and the tools required to deliver Drupal sites with a sale price of $100 per site. In this post I’ll be covering some of the considerations when building Drupal platforms or distributions.

The sites which customers deploy will need to be based on a custom Drupal distribution or “distro”. The distro should be modular and primarily driven by Features.

Customers shouldn’t have to know anything about administering Drupal when they first buy their site. A customer should be able to turn functionality on and off as they want, through a simple user interface.


The platform should contain a good collection of Features. The following list is an example of what you might offer customers:

  • Contact Form
  • Image Gallery
  • Products
  • Services
  • “Static” Pages
  • Blog
  • News
  • Mailing Lists
  • Social Network Integration
  • Office / Store Locations
  • Staff Profiles

When developing your list of things to include in the site, think in terms of functionality a small business would want, not what modules you should be using. The list of modules should be derived from the functionality, not the other way around.

As the features included in the platform will be modular and generically useful, you should consider releasing them publicly, via your own features server or drupal.org as full modules.

On top of the features listed above you will probably need to include some custom glue code to enhance the user experience. In my first post in this series I discussed the target audience not having high level computer skills, so the user interface should take this into account. Some of the language might need to be changed or form options modified to use sane defaults and some might even be hidden from the user.


As each server may have hundreds or even thousands of sites running on it, security will be an important consideration. Like with all servers you should ensure it is properly locked down and only running the services you need. Apache should be configured to block access to most things except index.php and relevant client side files (images, css, js) and the files directory. At the Drupal level you should make sure that things like the PHP module aren’t enabled and secure coding practices are adhered to. The user account given to your customer shouldn’t be user 1, they should be user 2, with restricted permissions that only gives them access to what they need.

I strongly recommend that you read Cracking Drupal by Greg Knaddison.

Sales and Support

In order to attract customers you will need a site to promote the service and allow customers to sign up and hand over their credit card details. Drupal now offers 3 ecommerce projects, Drupal e-Commerce, Drupal Commerce and ubercart. You should investigate which of these best suits your needs. The sales system will need some custom code to hook into Aegir, which will be managing the actual site deployments. The sales and support platform/s should be managed in a similar manner to the customer sites.

Once you have paying customers, you will also need to provide them with some resources such as detailed documentation, video walk throughs, forums and possibly a ticketing system. This site can either be part of the sales site or a separate site. In the next instalment I’ll cover support in more detail.

Deploying Platforms

We need to keep the whole process very automated, CPU cycles are a lot cheaper than workers. Building and deploying platforms should involve a few clicks or tweaking a configuration file. For example platforms could be built as Debian (or Ubuntu) packages (aka debs) using an automated build process that runs a test suite against the code base before building a deb. The debs could then be deployed using puppet and a post installation script can notify Aegir that it has been installed successfully. The whole process could involve very little human interaction. Migrating client sites to upgraded platforms could also be automated using a simple script which adds a migrate task for each site.

What’s Next?

Now that we have the service almost ready to go, we should look into how we are going to get customers to part with their cash and how we will support them once they have paid.

Dec 26 2010
Dec 26

In the previous instalment of my $100 Drupal site series I covered resources and infrastructure. In this post I will be covering the development tools I think you need in order to build and sell Drupal sites at the $100 price point. Given that Drupal 7 is close to release, it is assumed that the sites will be built using D7. I don’t believe that it is smart to invest heavily in Drupal 6 for new long term projects, given D8 could be out in 18 months and D6 would then be unsupported.


You are going to need a version control system for storing all of the code. There are many different version control systems available, but I think git is the most flexible and powerful option. Git allows for distributed development, offline commits and best of all, Drupal is switching to git. Gitorious is an open source clone of github which allows you to browse your git repository and manage integration of code from all of your developers.

If you are new to git I strongly recommend you get a dead tree copy of the book Pro Git.


Drush is the DRUpal SHell, a command line interface for Drupal. It is an invaluable tool for developing and maintaining Drupal sites. Simple things like running “drush cc all” to clear all caches when developing sites, through to being able to sync databases from one server to another, or one continent to another, save many hours. Even if you’re only running a handful of sites, you should have drush installed on all of your servers.


There are a few modules which you should be using if you want to be able to create polished Drupal based platforms. My list includes:

  • Features module allows developers to package up configuration as a Drupal module, including access to all the normal hooks that a module can implement. Feature is version control friendly and includes the ability to reset to a known good state, either via the Drupal web GUI or by using drush on the command line.

  • Strongarm exports values from Drupal’s variables table, allowing sane defaults to be set. This means your site will always be configured the way you want it to be.

  • Context allows you to manage contextual conditions and reactions for different portions of your site. It gives you control over displaying blocks,hierarchy of breadcrumbs, themes and other context sensitive configuration options.

  • Admin is a menu module which makes it quick and easy to access items. (Disclaimer: I co-maintain the module)

  • Coder can perform static analysis of your code to ensure it is secure and complies with the Drupal coding standards. The module can also be used to upgrade code from one major version of Drupal to the next.

  • Devel is a collection of tools to help developers create Drupal sites and modules. Devel integrates with Admin to provide easy access to the devel actions.

  • WYSIWYG provides a pluggable framework for integrating rich text editors into a Drupal site. Given the target market for the $100 sites, we can’t expect our users to hand craft HTML, they’ll be expecting “something like Word”.

  • Skinr provides a way for end users to apply predefined CSS to designated parts of a site, without the user having to understand CSS.

Installation Profiles

When most people install Drupal for the first time they are blissfully unaware that they are using an installation profile. An installation profile sets out a base configuration for a site that is installed by Drupal. Until recently installation profiles contained a list of modules to install and a large chunk of hand crafted PHP code which setup all the configuration for a site. These days most of the configuration can live in Features and so an installation profile can be very lightweight. It is worth reviewing some of the more popular installation profiles, such as Open Atrium, Managing News or Drupal Commons, for inspiration. Installation profiles have changed a lot in Drupal 7, so you will need to port the ideas to the new way of doing things.

Drush Make

Drush Make is a tool for building Drupal platforms. Drush Make allows developers to specify all the components of their site in a text file, then use the command line tool to “make” the site. It is possible to specify a version of Drupal core (including Pressflow), contrib modules and themes, third party components, patches and external libraries.


Aegir is a Drupal site deployment and management tool built using a collection of Drupal modules. With Aeigr you can manage your DNS, http (web) and database servers from a common UI. It is possible to move a bunch of sites from one server to another in a matter of minutes, not hours and the downtime will be measured in seconds. When security fixes are released, testing can involve a few minutes of work then a few more clicks to deploy it to all of your sites.


Instead of me explaining development workflows, I’ll defer to Miguel Jacq (aka mig5). Miguel’s blog post entitled “Drupal deployments & workflows with version control, drush_make, and Aegir” is considered by many to be the key work on modern Drupal development workflows.

What’s Next

Many of the tools I’ve covered today should be in your Drupal developer’s tool bag. My next post will cover what I think are the important considerations in building the platforms for the service.

Dec 26 2010
Dec 26

I’m back from Drupalcamp Athens. When I met Nektarios Sylligardakis and George Papadongonas in Copenhagen they told me Greece was a Joomla country and Drupal wasn’t well known, so my expectations were not very high. That’s why I was so surprised. Not only did I find a large and warm community, but I found myself waiting for the presentations to start so I could learn new things.

Since my Greek sucks, and since they understood that their presentations can have an appeal world-wide, most of the people gave the presentations in English. Varnish, Cloud computing, Security issues, Crazy clients with crazy demands and even crazier implementations were some of the topics. Not all movies have been uploaded yet, but here are at least some of them. It’s worth watching.

Although my stay was very short I still had the chance to see the Acropolis a la Robert Douglass style. This means storming out of the hotel - because my presentation starts in less than two hours - jumping inside a taxi, checking out every spot really quickly, taking a photo or two, back in the taxi, and we’re back. It was much fun!

Here is my own presentation about Organic groups for Drupal 7. I think it is a good introduction for those who still try to understand the concept of Entity and Fields and how it changes the way we approach a task in Drupal 7.

[embedded content]

Dec 24 2010
Dec 24

In my previous post in this series on the $100 Drupal site I outlined a possible target market and set out why I thought very low cost sites could be a viable business model. Today I will cover the resources and infrastructure you’d need to consider to build such a service.

I am not proposing that the business is built on the premise of working for $5 per hour to build new sites for each client. The whole business should be automated. There should be no need for human interaction to close the sale and deploy the site. As soon as a worker is added to the process costs start to rise. At the same time we need some skilled professionals to build the platform and the cookie cutters.


Building a very basic Drupal site doesn’t involve that much skill, it is possible for someone to signup with a web host that uses an automated installer script, such as Fantastico, and then start building a site using stock Drupal core. Building great Drupal sites takes skills and knowledge. In order to build modular Drupal sites that can be used as part of installation profiles and deployed using automated processes, you will need someone who knows Drupal pretty well. The person driving development of the project should be passionate about Drupal as a platform. They are likely to have an opinion on the Drupal specific religious wars - Panels vs Context, CKEditor vs tinyMCE, which Slideshow / Carousel module to use etc.

Most competent PHP developers can be taught how to develop for Drupal. A second, junior, developer can be used to do a lot of the build work. They can start being a “click happy” developer and as their skills grow they can get their hands dirty writing glue modules and patches. This person should be good at driving the Drupal GUI and working with contrib.

Designer / Themer

Although customers will only be paying $100 for their site, they won’t be very impressed if they can only use Garland as their theme. They will expect a choice of themes. The themes should be designed from the ground up to be flexible Drupal themes. The designer should have experience creating designs that will be come Drupal themes. They should understand flexible regions, module themeing and how the Color module can be used to provide control to the user over their theme. Ideally the designer should be able to craft HTML and CSS, and even perform basic Drupal themeing.

System Administrator

Even though the plan is to keep costs low, it doesn’t make sense to run the $100 sites on cheap shared hosting. You need to spend money on your own solid hosting infrastructure, and if you have your own hosting infrastructure you’ll need someone to manage it. The sys admin will be responsible for keeping everything running, adding new servers, testing backups etc.

You will need a system administrator who has some experience with administering LAMP servers, previous Drupal experience is a big plus. You want someone in this role who hates downtime.


One of the assumptions for this project is that 95% of the sites will have less than 50 page views per day. At first there will be very little traffic for the sites, so you can start off pretty small, but as the business grows you need to have a plan in place to handle that growth.

I wouldn’t recommend spending a lot of money on buying servers outright and putting them in a data centre. Start off with some virtual machines from a cloud hosting provider, such as slicehost, linode, Rackspace Cloud or Amazon AWS. By using cloud hosting providers you can scale your infrastructure up as you need.

To get started you will probably need 3 production virtual machines, one for serving up content, one for the DB and one for search using Apache Solr. Each of the VMs should have 1G of RAM and be located in the same data centre with the same hosting company. When things start to grow you can scale up the VMs as you need and even add more servers. Each time you scale things you will also have to retune your configuration. An opcode cache such as APC or xcache will allow you to serve more requests on the same hardware. You should include some kind of monitoring service such as nagios or zabbix to make sure things are running as you want.

Once you have more than a handful of machines to manage, you will want a centralised configuration management tool. This will allow you to add new servers and have them configured as you want them with no (or very little) human intervention. I would recommend puppet for this job. Given the effort involved in retro fitting puppet in an existing environment, it will be easier to add it from the start. You may want to consider using libcloud to even handle the deployment of the VMs too.

To ensure everything can be tested properly before deployment, you should seriously consider having a replicated testing environment. Instead of having 3 more VMs, you can just run up a Linux box with 4G RAM and a relatively modern CPU and run 3 VMs on it using KVM or Xen.

What’s Next?

Now we have the business plan, the market, the team and servers in place, it is time to start looking at some of the tools we’ll be using to make all of this possible. The next post in this $100 Drupal site series will cover the tools needed to build a sustainable platform for the business.

Dec 24 2010
Dec 24

In late October Gdzine posed the question “$100 CMS web site feasible? What do you think?” on LinkedIn and the question was also posted on groups.drupal.org. These posts lead to lengthy discussion threads. Some people accused Gdzine of trolling and others claimed that it wasn’t possible, but a few of us argued it was possible to build a Drupal site for $100.

Over the next week or so I’ll be blogging how I would go about delivering $100 Drupal sites. $100 is in United States Dollars. I won’t be providing a complete blueprint, but there should be enough information to help get you started.

I have some experience building large numbers of production sites using Drupal for a small price per site. In 2009 I built, deployed and managed 2086 sites for a European client. For most of this year I have been offering training and consulting around some of the tools and techniques this blog series will cover.

Is it Feasible?

Several companies already offer low cost Drupal site solutions. Acquia’s Drupal Gardens is probably the most well known cheap Drupal site building service with its freemium model. Wedful offers a Drupal based site for couples getting married for only 95USD for the first year, then 25USD every following year including hosting. Spoon Media’s Pagebuild service offers a customised Drupal platform for 30USD per month. I am sure there are others operating in the same space. wordpress.com offers a similar service using WordPress. I have no idea how financially viable these businesses are, but I think it is safe to assume that they’ve done some research and planning to get to this point.

These services all rely on making their money on the turnover rather than the margin. Most consultants, myself included, make our money by charging a good hourly rate, but we only get paid for the time we work. These services rely on investing up front then waiting for the long tail revenue. For example if you invest 50,000USD up front into building the service, then you have to sell 500 sites just to break even.

Target Market

In order to make these services viable, you have to target a particular market segment. Customers for a $100 site are likely to be “mum and dad” businesses, they don’t have a lot of money to spend and are also unlikely to have a lot knowledge about the web. A lot of the customers are likely to think “the internet” is that blue e on their desktop or Facebook. I know of several small businesses who think that Yellow Pages advertising is not giving the return on investment they want, but can’t afford 1500-2000USD for a decent quality brochure site. These are the people this service should be seeking to attract.

Why Bother?

Most Drupal developers aspire to work for switched on clients who want high quality sites. Working with well known brands is always a bonus. No one is really going to be interested in hearing about how you built the site for “Joe and Jo’s Diner”. There is still a lot of problem solving involved in building a service like this, but these problems are very different to those found in large scale site builds. Also many of the people seeking a $100 site are likely to be high needs clients who undervalue the skills involved in building a site.

What’s Next?

All posts in this series will be tagged with “$100 drupal site”. In my next post I will cover what I think you need in terms of infrastructure and resources to make something like this work.

I have proposed a session for DrupalCon Chicago on this topic, please consider voting for it.

Dec 23 2010
Dec 23

Drupal 7 has cost enormous blood, sweat and tears. Now's the time for celebrating. And hey, there are the release parties. To combine this with marketing, there is something else we could do. The style of this video struck me.

So we will create something in the likes (only better, of course). This is a kickoff post to make you do the small videos that we cut into a big one at the end. Graciously, 300+ has offered to do the video editing and they are good at that.

The video will contain: Statements from you on why Drupal 7 is so great, and a big countdown that leads into people welcoming Drupal 7 like the new year on New Year's Eve.

Release Parties: the perfect occasion

We guess the release parties are the most appropriate space to whip out your mobile video recording device of any kind, and show us what you got. Working title: "Seven is seconds away".
If you record some videos before the parties and upload them to YouTube, it is much appreciated. So we can market the effort more..

Here is a video that explains what we need from you all to make this rock:

Steps to stardom

As explained in the video, I repeat the steps here once more. Do the video on your own, or do it with your pals. The more pieces we have, the greater the end result will be.

1. Make a statement

about what you think about Drupal 7. What excites you most? What does it mean to you personally?


"It's so easy now, my granny will build a site with it tomorrow."
"Two words are enough: cutting edge."
"Thanks to everyone who put so much work into it"

2. Count backwards

somewhere between 60 and 0

About 20 numbers are enough. To synchronize, best use a metronome, so you can look at the camera while counting. Set the metronome to 60 beats per minute. Here is a free one for Android: www.appbrain.com/app/mobile-metronome/gabriel.metronome

3. Give a release cheer

Let us feel your positive energy while shouting "Releeeease". Supporting gestures much appreciated.

4. Go wild with cheering

Groups have an advantage here. If in doubt, consult the air guitar wold championships for inspiration in planned madness. If you are good, they can hear you in Helsinki.

5. Upload your video and notify us

Upload the video to your webserver or any video platform (YouTube preferred) and post a link to it as a comment to this post.

For best video quality it is preferred you upload your finished video onto some webserver and send us a download link (as a comment to this post or per mail to the undpaul contact email). So we have an uncompressed source file for editing.

If you find it easier, you can also upload the videos to YouTube. We are not sure if all these little videos on YouTube make sense, so decide yourself: If your video is a fun piece in itself, upload it anyway. There is no limit in including more improvised madness than the four points we need...

Since YouTube does not have groups anymore, we need to collect the videos differently: tag them "drupal-7-release". Also best start the title with "Drupal 7 Release" so we and other people can find them. Maybe "Drupal 7 Release Sam Boyer shows what he thinks of it..." To have a playlist in the end that shows all the pieces and the finished big one might be interesting :)

With your help, we can create a very lively video that can be a great marketing resource for Drupal 7 and some time after.

Dec 09 2010
Dec 09

Ever wondered if your Christmas Tree is really any good? Well last weekend I decided to make a website for this purpose. It's just a bit of fun really! You login using your Facebook credentials (using Facebook Connect) and can create Chrismas Tree posts by linking to Flickr or Facebook photo's. You can then vote on your favourite tree's in an "A vs B" type match. If you like the sound of this and fancy something a bit festive, please give it a go and let me know if you have any thoughts! Head over to Rate My Christmas Tree :-)

I've published one of the modules this site produced: Media: Facebook. This module allows you to embed a Facebook photo into an EmField by simply copying and pasting the page URL from Facebook. The module then usesthe Facebook API to lookup all available sizes. It is a beta and still needs work, but certainly covers the basics.

I've also written a custom module for comparing and voting between two nodes. I looked into the Voting API (which is AWESOME), btu it only allows you to store a score aginst a single node. I need a system which defined a "left" and "right" node and a "winner". I also looked into the Smackdown module, which looks great too - however that seems to force you to create a "competition" node for every competition. That could get out of handy very quickly (assuming the site gains any kind of traction). So I wrote a module called Compare (which I've not released yet). It will allow you to create "profiles" of votes. Each profile has it's own role-level access control and stores the User ID, Left, Right, Winner and Timestamp of each vote. The vote URL also uses Drupal's private key system to generate secure URL which is limited to only work for a certain period of time. The hash used to secure the URL also stops people changing the left, right or winning Node ID to anything other than that intended. I want to do more work on it before I release it though.

Dec 04 2010
Dec 04

I came across a problem with a panels page when I check the "Disable Drupal blocks/regions" box, the sidebars are supposed to disappear so that the content takes the full width. But it didn't work.

Switching back to Garland and the sidebars disappeared as expected. After a quick search, I found this post on drupal.org which is the same issue but one of the replies essentially says to hack core to get it to work, but that is not necessary.

In Drupal core, it only looks for sidebars named left and right. I have 4 (left_sidebar_primary, left_sidebar_secondary, right_sidebar_primary, right_sidebar_secondary), this allows me to style some blocks easier dependent on their weighting in the sidebars.

The workaround is very simple. All it requires is a few lines in your template.php file in your hook_preprocess_page() function.

If you haven't that function in your template.php file, then here is the necessary code:

  // Code goes in here

The code which we need to enter is fairly simple.

  if (!$vars['show_blocks']) {
    $vars['left_primary'] = '';
    $vars['left_secondary'] = '';
    $vars['right_primary'] = '';
    $vars['right_secondary'] = '';

Here we check to see if the $vars['show_block'] variable is FALSE, if it is then we set the content of all the sidebar regions to nothing.

If you would like to disable more regions, just add them as they are defined in your theme_name.info file.

One other thing to mention is that you need to make sure in your page.tpl.php file that you correctly add the code to not show any HTML markup if the region is empty.

if (!empty($left_primary)): ?>
    print $left_primary?>

endif; ?>
if (!empty($left_secondary)): ?>
    print $left_secondary?>
Dec 01 2010
Dec 01

I've been working with custom PHP MySQL apps for quite a few years. Early on I was building grant systems for nonprofit and State Arts Agencies in the United States. About 4 years ago, I fell into Drupal quite by accident at a little think tank that my then employer, The Western States Arts Federation, had organized in Vancouver. Several of the participants were employees of Bryght. I began to drink the cool aid. While at WESTAF I was responsible for the build of a couple of Drupal sites and found myself more and more drawn to the modular LEGO-like way you could snap pieces together to create something new. It was just about at that point that I starting going to Drupal meetups and transitioned to a Web Producer position with a Drupal shop. This was the beginning of my seeing Drupal as my bread and butter.

Fast Forward to November 2010. I've been to Drupalcons in Barcelona, Boston, Washington, Paris, Copenhagen, and San Francisco. I was involved in helping set up the original Drupalcamps in Colorado when you could count the participants on two hands and that has grown to several hundred. Austin was the first camp I attended outside of Colorado and I was impressed. Six out of the Seven Vintage Digital Co-op members attended.

I approach each of the meetups, cons, and camps as a place to potentially grow my understanding of Drupal as a profitable platform. They give me a chance to meet with leaders in our community, with other Drupal Professionals, and interact with different shops of different sizes. The sessions often validate and sometimes surprise me. In Austin, I attended nine sessions including Jeff Robbins' keynote. I wrote about each of the sessions on my personal blog. They are really just notes with video from the event - but if you have interest you can see them on dogstar.org tagged with drupalcamp austin. I was happily met with a few new community modules, mostly surrounding SEO, that I hadn't heard of before. I enjoyed the panel on Managing A Drupal Business. Panels like this allow people to validate what they think they know by hearing similar stories from other businesses.

I am seeing more and more of the office managers, accountants, content creators, marketers, and account managers at these events. This should be encouraged and more business track sessions ought to be solicited. As Drupal continues to mature and ease itself into the Enterprise we need to grow with it widening the pool of talents beyond project managers, developers, and themers. We need to thinking in strategic ways and leverage those who have traditionally not been within our community. All of what I'm seeing is encouraging.

It is easy to discount the social time at the camps and conferences. However, meeting people in a looser way at places like Austin's Dog and Duck Pub is also very important. These are the times that professional contacts are made, deals are often brokered, and jobs are offered. Conversations can be had that help you avoid technical and project oriented pitfalls that other developers have found themselves subject to. You might find out about an RFP that a friendly competitor isn't going to bid on because they are out of bandwidth.

Austin was an inexpensive way to feed the need for professional development and to continue to forge and support relationships. I, personally, am looking forward to more camps.

Nov 29 2010
Nov 29

Design Camp Prague was great. I met quite some people I did not know. A strange feeling to be in a Drupal crowd that was not dominated by developers... Well, actually it was not dominated by designers either. The Drupal design community consists of up to 98% of themers, or designers that know a lot about coding.

On Sunday very early in the morning (regarding the fact that the camp crowd hit the Prague nightlife really hard the night before) we had a brainstorming session about how to get more designers into the Drupal community.

Who is a designer?

Well, even trying to define what a designer is needs a consensus. Being the host of this memorable session, I tried to gear it more in the direction of artistic designers that know little or nothing about coding, the most they would know is HTML and CSS, but no PHP (run and hide). It is this group of people that are really good at aesthetics but that hate coding that Drupal sorely lacks. Concerning people that are active in the issue queue, we had a consensus in another session that you cannot count more than four in all of Drupal. (which may be wrong, but it sure feels like this).

Possible motivations for designers to get involved

The interesting thing is that a visually oriented designer (what a bad term, but I hope you understand ;) ) could gain quite a lot by participating in Drupal. Here are some ways they could:

Participate directly in Drupal:

  • Work on the redesign of drupal.org
  • Create a new theme for Drupal 8
  • Create a free theme to be hosted on drupal.org
  • Sell commercial themes from their own site ore one of the big template shops
  • Help out in UX Design of Core or contrib

What could they win?

  • Create a contrib theme that is installed on hundreds of sites, and stands out visually from other Drupal themes. Try this in WordPress - very hard, since there are so many good themes around. Much easier to do in
  • Create a contrib theme that gets installed on thousands of sites (think Acquia Marina). In contrib land it is tolerated that you put a backlink to your site in the footer.
  • Become famous
  • Become famous and be hired by a Drupal shop to do the design for the next whitehouse.gov
  • Add a new skillset to your portfolio: knowing Drupal. Not every designer hates being a themer. Learn to theme and add even another skill set to your portfolio.
  • Get rich. Drupal projects can get quite huge, and designers and themers often earn good money as all other Drupal-workers. This is a lot different in WordPress-Land.

Big Plans in Prague

We had quite some ideas how to improve the situation and how to make it easier for artistic designers to get involved in Drupal.

Designer Starter Kit: creating themes made easier

Creating Themes for Drupal is hard for a Designer coming new to Drupal. When we tried to figure out why, the main reason to us wasn't even a technical one.
As the biggest obstacle we saw that you cannot even define what Drupal is. Opposed to WordPress, which will almost always be seen as a blog system. Create a theme for WordPress - create a blog theme. You come to this idea quickly and already have a picture of the use case in your mind.

Not so with Drupal. It can be a brochureware, shopping cart, wiki, blog, social networking site, forum, news portal... where to start?
So we decided to create an install profile to cater exactly that need. While we have not fully decided which direction it will take - Blog, Brochure or just displaying core content types like http://demo.kiwi-themes.com/drupal-dev/, the general plan is layed out.

We created the Designer Starter Kit that will ultimately lead to an install profile that gives Designers an immediate starting point for their Drupal theme. Having some sample content and looking like a small site, it gives a use case. It will contain an empty theme with all files necessary to start. There will also be a Readme file and a tutorial video (or even several) how to start. If we can keep designers away from template files and start by modifying CSS only this should help a lot. It turns out the idea is not new...

Also thought to be included is a Photoshop file that contains all elements that need to be designed for Drupal: comments, author information, login block, book navigation... The plan has to prove itself as the project goes on and sure we need to find out if it is really helpful.

If you have a basic install profile for Drupal 7 with some sample content that could be useful for DSK: upload it to the issue queue of DSK, we are collecting these to compare and build one or more that are really helpful.

Creating and improving drupal.org/design

The first and most probable place to go when you want to know anything about Drupal is drupal.org. Now if you are a designer, you may look for a place that gets you started, but you won't find it. You will wind lots of theming tutorials, very technical and telling you all about page variables and preprocess functions. But if you are a designer in the aforementioned sense and are visually and artistically inspired, you will quickly come to the conclusion: "Drupal is not for me".

This has been discussed many times, and Mogdesign started an initiative in Copenhagen by announcing www.drupaldesigners.org/ in order to create a place where artistic Drupal designers could meet and exchange ideas.

Discussing this with Mogdesign, it was clear that creating a resource off of drupal.org is not the optimal way. Though d.o. puts constraints on what you can do there and consensus needs to be found with webmasters and all other people involved, the central place is more powerful and makes a lot more sense.

So what do we need to do on drupal.org/design? It could be a lot, and there is already an issue for this: www.drupal.org/node/898110 It needs to be fleshed out what is needed to welcome designers on d.o. A few ideas here:

  • Gallery of beautifully designed Drupal sites
  • Links to resources to get a quick start into designing for Drupal
  • Gallery of beautiful Drupal themes
  • Links to design-related forums, channels, and g.d.o groups
  • The page needs to be beautifully designed to appeal to visually oriented people

Create a space to contribute by uploading layouts and more

Another idea we had: the easiest way a designer can contribute is by showing a design. Just like Jeff Burnz once started: how to create a place where designers can contribute their layouts and themers offer to make Drupal themes out of them? Taking into consideration the benefits for the designers in "What could they win" above, there might be incentives to contribute a design.

What else needs to be improved to make it easier for aesthetically oriented people to get involved

  • Make it easier to upload images on d.o., especially on the issue queue. Uploading an image to the issue queue is next to impossible for someone new to d.o.
  • Offer help with CVS and Git to enable Designers to create a contrib theme on d.o.
  • lots more, you name it...

Spotlight on you

All these ideas need people to step up and make them real. A place to discuss is the Design Group on g.d.o. To really get something done, the issue queue is a better place for sure. The channel on IRC would be #drupal-design.

If you want to contribute you can also just leave a comment on this blogpost, we'll try to guide you to the right place and give help on how to get started.

Nov 26 2010
Nov 26

Webform is a great module to build simple to complex forms for users to fill out, but it has no built-in way to trigger events for Rules. Unfortunately the maintainer is not going to add this kind of functionality anytime in the near future.

Drupal wouldn't be Drupal if you couldn't get around this issue by writing a small module.

The following code triggers an event upon sending the webform, which can be used by Rules. This is useful if you would like to send an email or display a message when the webform is submitted or use any other kind of available action in the system. The current user as well as the webform node and the form data are delivered as a parameter to the executed rule.

Contents of webform_rules.module: Contents of webform_rules.rules.inc: array( 'label' => t('A webform has been submitted'), 'module' => 'Webform', 'arguments' => array( 'user' => array('type' => 'user', 'label' => t('User, who submitted the webform.')), 'node' => array('type' => 'node', 'label' => t('The webform node.')), 'data' => array('type' => 'data', 'label' => t('The submitted webform data.')), ), ), ); } ?>

After installing the module you will see a new entry in the list of available events when creating a new rule and you'll be able to use the webform data.

Download and test the module

If you found any errors while using the module or have support questions or think a new feature would be cool to be integrated use the issue queue of Webform Rules. This will reach a wider audience and increases the chance of an reaction ;).

Nov 08 2010
Nov 08

On Oct 16/17th we held the Drupal 7 Sprintcamp in Hannover. We met with 40 Drupal Workers of all flavors to give a boost to Drupal 7. Beyond the main focus on D7 we also dived headlong into more general Drupal stuff.

Our beautiful venue was the Coworking Space Hannover. On three floors we had plenty of space. We worked on four topic groups: Coding, Documentation, Marketing and Translation. The official organizer was the Drupal Initiative Germany, which is our local mini-version of the Drupal Association. undpaul did all the practical planning and organizing. We managed to attract quite some sponsors, and thanks to them we could keep the camp completely free for attendants, including drinks, food and a saturday night event in a nearby pub. A big thank you to the sponsors!

We chose coordinators for each topic group to have better organization and to have someone to talk to for the sprinters at all times if they ran into problems or out of work.

Coding and translation

Stefan Borchert (stborchert) was responsible for Coding. The biggest chunk worked on was Views, mostly Views for Drupal 7, of course. As the co-maintainer of Views, Daniel Wehner (dereine) was there, we had fixed over 20 Views issues by the end of the weekend. Karsten Frohwein (Kars-T) did a little introduction to Simpletest so with the help of thus newly-trained people we were able to write some new tests for Views.

Besides Views we worked on some other modules:  Login Destination to Drupal 7 (though the patch is still pending for acceptance).  ThemeKey, which has an Alpha 2 now, and we made some serious progress on Content Access and Scheduler.

To sum up we found out that writing tests gets too little attention; especially for Views a lot of tests are missing. This includes writing Simpletests, but also just manually trying out Views and submitting patches. So anyone who is not a coder but wants to have Views ready with the Drupal 7 release: hop in and go for it. Install Drupal 7 with Views 7.x-3.x, create some content and a few Views, hit a wall and file some issues. This is much more valuable than you might think.

The Translation team used our great existing infrastructure on localize.drupal.org to translate Drupal 7 core and quite a few modules like Admin, Context, Pathauto, Features, Strongarm and more. The team was led by Anja Schirwinski (aschiwi), and besides translating they tested beta.drupal.org and helped improve http://drupal.org/features as well as the new website for the Drupal Initiative, which needed a new design, better structure and some text.

Documentation and Marketing

Floh Klare (SirFiChi) led the Documentation team that chose a very thorough approach with the status of the German documentation, which is hosted on drupalcenter.de. Not pleased with the lack of structure, they started over on tddp.de and rebuilt the thing from the ground up. Starting with a well thought out structure, most of the content is still lacking. But the plan is to migrate all the documentation content over time from drupalcenter.de, which was started on the weekend, as well as creating some great new docs. The main features are advanced filtering, which are found in the doc finder. Instead of relying on building the classical tree structure the team focussed on a user that would be likely to use search instead.

But it was not only the German docs that got some boost, also the English docs for Views 3 were extended, which went directly into the advanced help section of the module.

The Marketing team, led by Thomas Moseler (eigentor), faced a bit of a blank slate: we do not have any marketing for Drupal, especially in Germany. But especially over here it is badly needed, as Drupal is by far not as popular here as in the US. The strategy for the weekend was twofold: on one hand a presentation site, that is to be imagined like an extended drupal.com, that was continued to build. The idea is not new and Sebastian Daniel (s.Daniel) has already created a great design and thought out a basic structure. The site will serve only marketing and information purposes mostly for Drupal newcomers.

Similarly to Acquia's home page, this will be divided by four target audiences: decision maker, designer, coder and end user. These four personas also were the basis for the structuring of content that is going to be put on that site. A smaller group worked on creating and structuring the site, while the major part split into subgroups to collect the major advantages that could convince each of the personas to choose Drupal over another CMS.

There were lots and lots of discussions, sheets and whiteboards full of brainstorming results. In the end we managed to prioritize the results while not being finished. But we could be sure to have thought of really a lot, which is to be found in the sprintcamp forums, which document the progress of the other groups as well. What the marketing group must do now is still better prioritize the results, so we can put them on the presentation site that will hopefully launch in late 2010 or early 2011.

A busy and intense weekend, but we still managed to have nice evening events in the nearby pub "Spandau". The cosy and pleasant Coworking Space helped us enjoy it and not to get too much into a workday mood. From our side - we will definitely do it again :)

Oct 30 2010
Oct 30

This tutorial shows a quick and easy way of creating an inline image gallery.

Our goal is to add an arbitrary number of images to content (say of the content type "page"). We want to be able to freely choose the position in the text for the images. On click we would like to display a magnified version of the image.

Required modules

Step 1: create Imagecache presets

First we create two ImageCache presets that define the thumbnail (which is visible in the text later) and a bigger version for the magnification effect.

The settings shown here are only sample values of course, and can be changed to your liking later.

Step 2: Adding a field to the content type

After we have defined the ImageCache presets, we can extent the desired content type. In our case I am using the content type page as an example.

Those are the example settings: every image uses its own directory inside sites/default/files and you can also give a seperate title to every image.

Now the settings for inserting the image into the content. In the image settings, there is the area "Insert" for this task, in which we can choose how to insert the image into the content. Since we are working with Colorbox, we choose the option "Colorbox" with our "Thumbnail" ImageCache preset.

To complete this, a few general settings for the new field are created. Among other things we can define here how many images can be inserted.

As a small addition you should also define to not render the values of the imagefield (Display Settings of the content type). Otherwise the images would be visible below the content for a second time.

Create content

After finishing the field settings, we can now create content and insert images into it. To do so you choose the desired image, optionally give it a title and then click the button "Insert" next to the image. In this way the HTML code for the image is inserted into the body text at the current cursor position.

As we have chosen in the image settings to use Colorbox, a link around the image is created in the same step as well as the classes that Colorbox needs.

Before saving be sure to choose an input format which does not remove the HTML elements and attributes. As a quick solution I have chosen "Full HTML", but you should not allow this format for every user on a live page.
It is more secure to define an additional input format for this purpose.


If we save the content with the inserted images as now, the images are shown in the middle of the text. Clicking on the preview images opens a bigger version of the image with Colorbox and one can also step through all the images that are inserted into the text.

Oct 20 2010
Oct 20

[Edit: I have found a better solution that allows using CSS3 on IE as-well – CSS3PIE]

CSS is annoying and I’d like to deal with it as little as possible. For that I’m using 960 grid design, I’ve started looking into LESS, and the latest is a rewrite I did to the Rounded corners module.

Rounded corners is no longer a “dumb” wrapper for the jQuery plugin, but rather an API that lets you do what you want with as little code possible.

  $commands = array();
  // foo class will have default rounded corners.
  $commands[] = array('selector' => '.foo');

  // bar class will have 5px rounded corners on the top.
  $commands[] = array(
    'selector' => '.bar',
    'width' => 5,
    'corners' => 'top',

  // Add the rounded corners.

As a bonus feature you can also add rounded corners on images! Here’s a summary from the README.txt:

Round corners can be used on images, by selecting the wrapping div (not the itself), and by settings the “image wrapper” property to TRUE. for example, consider the following HTML:


And the PHP code:

  $commands = array();
  $commands[] = array(
    // Select the wrapping DIV.
    'selector' => '.image-wrapper',
    // Let the module know this is a wrapping div of an image.
    'image wrapper' => TRUE,


With the above code, the plugin will not try to use the browser’s native support for round corners, thus will insure the image corners are properly “hidden”.

It might not server for all cases, but I do think it can save time with some annoying tasks. I was also trying to do the same thing with Drop shadows, however since the jQuery plugin is quite old, and as far as I see not maintained, the results are so so. You can check it here.

Oct 14 2010
Oct 14

This weekend, undpaul is proud to present the Drupal 7 Sprint Camp in Hannover in collaboration with the German Drupal Initiative. Note the absence of "code" in the name ;) We are happy to cover non-code topics to the same extent that we will be doing coding, of course.

From its announcement, the sprint has quickly been a sell-out success. The 40 available places were quickly taken without even a real announcement. A testament to the vividness and commitment of the Drupal community ;)

We will be sprinting at the Coworking Space Hannover this coming weekend on Sat/Sun 16/17 Oct. with an opening socializing event on Friday night. On the sprint days, we will be working in four groups: coding, marketing, documentation and translation. Each group has its own team lead to coordinate better and to have someone to speak to for the team members at all time. People that wanna participate remotely, can jump in IRC channel #d7sc this weekend. This channel will be german speaking but if we have a lot of english speaking participants, we will open another channel or use #drupal-contribute.

The topics

The concentration will be on modules rather than on core, and on meta topics. Personally I am responsible for the marketing section, which needs a lot of attention especially over here in Germany. In Germany, Drupal is not the leading high-end OSS CMS at all. In fact, it is doing so badly, that a big publishing house could not be convinced to publish a learning DVD about Drupal because market research tells them it won't get sufficient sales. Well, it is not that bad, but the fact is we gotta do something over here.

One special focus of the coding group will be Views 3 for Drupal 7: Views is quasi-core, and in order to being able to use Drupal 7 for real-life projects, it needs a lot of attention. As Daniel Wehner (dereine), co-maintainer of Views, says that the problem with Views 3 for Drupal 7 is that too few people (surprisingly) use it yet. There is actually a lack of issues, something unheard of in the views issue queue. So we will also focus to test it in a real-life environment to find the bugs - or verify the absence of them. Another quasi-core area of Drupal 7 that has gotten too little attention is the upgrade path for CCK. There are voices that say it should be core issues, but to get Drupal 7 out the door, we simply cannot afford this. So hopefully we will be testing the CCK upgrade path and improve it as well.

We are looking forward to a great weekend. Expect to hear reports and see impact on the issue queue from us ;)

Oct 12 2010
Oct 12

Last weekend (Oct. 9./10.) the first Drupal Executives Meetup (DrupalCXO) took place in Brussels. DrupalCXO is a business event specifically for Drupal Executives and was held in in a venue provided to us by Microsoft. Microsoft also sponsored lunch and drinks.

The Executive Meetup was the first of an entire series, that are going to be organized collaboratively by European Drupal organizations. The plans were made at a meetup at Drupalcon Copenhagen, when representatives of these organizations met for the first time. The goal is to organize bigger and more international events specifically in Europe. This is meant to strenghten the European Drupal community, and also to give the opportunity to single countries to organize an international event. The events specialize in the most important topics: design, development and business. The plan is to provide at least one event per year for any of those topic blocks, but more is better.

At this first meetup there was space for 60 participants, the event "sold out" (it was free to attend) in only a few days. There were no scheduled talks, we used the Open Space concept to plan and hold sessions. Each of the two days started with planning talks together. The talks were then held more in the form of collaborative discussions instead of one speaker giving a presentation. This was the main reason there was relatively little tweeting and documenting - everybody was very involved with their entire attention. Favorite topics were how Drupal shops can collaborate better, how to build some kind of "Drupal Business Association" to have an official single point of communication. Furthermore improving the reputation of the Drupal brand for customers, certification and finding new Drupal talents were popular. Some of these ideas will be continued in future business camps. During the event it became clear how important the business aspect of Drupal has become, and that there is a lot of need for exchange.

Sep 29 2010
Sep 29

It’s time for some P.R. (Public relations) on the Message module, and the best way is a Message example module that loosely imitates Github’s news feed feature.

I won’t get into too much explanation here, just look at the screenshots, or try it yourself - since everything in Message is exportable, you don’t need to do anything to make it work! (Apart of generating nodes and “making friends” by flagging other users).

# Download necessary modules, in case you still don't have them.
drush dl ctools message flag views

# Enable the message example module.
drush en message_example -y

# Use Devel module to generate users and content.
drush dl devel
drush en devel_generate -y

# Generate  10 users.
drush genu 10

# Generate 25 story nodes with 5 comments in each node.
drush genc 25 5 --types=story

Navigate to /messages or click on the “News feed” on the navigation menu, and you will be presented with the different tabs - all created with Views and a bit of CSS.

As you can see, at the beginning there are no records in the “News feed”, because you still don’t follow anyone. Go to the “All feeds” tab, click on one of the user’s and flag the user or flag a specific node. Back in the “News feed” you will now see all the activity of the users and nodes you follow.

If you are not a developer worry not (although if you are a bit familiar with code, the message_example.module has lots of documentation), you can still use the Message module, thanks to its Rules module integration.

So, what do you think about this P.R. ?

Sep 09 2010
Sep 09

The Drupalcon Chicago 2011 track chairs met for the first time last week. Our first task is to come up with track descriptions. For the first time, Theming is going to be separate track from Design and UX. While this shows a nice focus on these interrelated but distinct topics, I'm still trying to come up with a good description that helps define the dividing line between design and theming for sessions proposals like “Designing with CSS3”.

Anyway, here’s my first draft for my track’s description:

Theming Track

As Drupal’s mighty hands build markup, styling and dynamic behaviours, the lowly Newbs have forever strived to comprehend this Magic. With gnashing of teeth, wailing and despair often being their pitiful state. But, lo! Behold the mighty Drupalcon Theming Track. Forthwith, We, the Gods of Drupal, beseech the worthy to attend this track and despair no more.
[insert thunder crack here]

Hmm… I may have to tone it down. A bit.

So with a theming track that will focus on the nuts and bolts of actually building design, interaction, usability, accessibility and navigation, what sort of sessions should we have in Chicago? And I mean what sessions do you want to see, not what sessions are you going to propose.

Sound off in the comments below.

Aug 25 2010
Aug 25

Apart from PHP bugs and Denial of Service attacks, there's another reason why calling unserialize on user-supplied data (cookies, hidden form fields) is a bad idea.

When a serialized object is unserialized, its __wakeup() member function will be called if it exists. Lesser known is the fact that another magic method will also be invoked. This is the __destruct() member function that will be invoked when either 1) all references to the object are removed, 2) when the object is explicitly destroyed or 3) when the script ends.

You can see for yourself with the following example code:

class someClass {
  public $foo;

  public function __destruct() {
    echo "__destruct(): Exterminate! Exterminate!\n";

echo "Back in main.\n";

function demo() {
  echo "Demo starts.\n";
  $s = serialize(new SomeClass());

  $u = unserialize($s);
  echo "Demo's over.\n";

This will output:

Demo starts.
__destruct(): Exterminate! Exterminate!        <-- no refs to the new result, object destroyed.
string(32) "O:9:"someClass":1:{s:3:"foo";N;}"
object(someClass)#1 (1) {
Demo's over.
__destruct(): Exterminate! Exterminate!        <-- $u out of scope, object has no refs, destroyed.
Back in main.

The first destruct happens when the result of new SomeClass() is destroyed, the second one when the $u variable goes out of scope and the last reference to the object is removed.

As all the member variables can be controlled by the person supplying the string, he (m/f/o) can cause a __destruct() member function to operate on unexpected data. Stefan Esser has used this to great effect; See Shocking news in PHP exploitation and the Piwik cookie unserialize vulnerability for how he was able to exploit this to run arbitrary code.

Drupal 7 also contains a __destruct() that, combined with the autoloader, can be used to delete arbitrary files from the system, provided the server running PHP has sufficient privileges to do so.

The __destruct() in question is a member function of Archive_Tar:

function __destruct()

function _close() {
  if ($this->_temp_tarname != '') {

So, if a module uses unserialize on user-supplied data, one can simply provide the following string (adapting _temp_tarname) to do damage:

O:11:"Archive_Tar":6:{s:8:"_tarname";N;s:9:"_compress";b:0;s:14:"_compress_type";s:4:"none";s:10:"_separator";s:1:" ";s:5:"_file";i:0;s:13:"_temp_tarname";s:0:"";}

Take away message: do not call unserialize on user-supplied data.

Aug 11 2010
Aug 11

A development virtual machine can be really handy. It gives you a sandbox of sorts where you can feel free to test and experiment knowing that in a worst-case scenario you can just delete the VM and start over. It can also be a great way to practice server configurations and sketch out "real-world" server setups. Here's the process I follow to setup my Ubuntu 10.04 LTS Drupal development VM in VirtualBox. Aside from the VM-specific steps, these instructions should work for a regular Ubuntu server (VM or not).

Download and install Ubuntu 10.04

Note: Unless otherwise specified, all commands below should be run on the guest VM (Ubuntu).

If you haven't do so already, download and install VirtualBox. Then, download the Ubuntu 10.04 LTS disk image to your host computer.

Next, Create a new virtual machine in VirtualBox. Be sure to select type of "Linux" and OS Type of "Ubuntu" and 32 or 64 bit, accordingly.

Start the machine and, when prompted to select a disk drive, click the icon to the side and open the Virtual Media Manager. Add the ISO file you downloaded to the list of disk images and select it as the media to mount. Walk through the install wizard. When asked to install software, don't choose any packages. We'll add them later. When asked to install the GRUB boot loader, go ahead and choose "yes." Once installation is complete, click on the CD icon in the VM window and unmount the disk image, then choose "Continue" to reboot into the Ubuntu server VM.

Update, upgrade, and setup SSH

Before we do anything else, let's get comfortable in the environment. Working in the small shell window that VirtualBox provides isn't ideal, and it'd be nice to be able to do the rest of the setup over SSH in the terminal of our choice. Install the OpenSSH Server package, upgrade existing packages and then shutdown the server (because we'll have likely updated "linux-headers-server" and other core OS packages, and also so we can do the next step).

If you'd like to make things easier on yourself and not have to type "sudo ..." for every command, run sudo -u root -s to become root for the rest of the session. Otherwise, be sure to add "sudo" before each of the follwing commands.

apt-get install openssh-server apt-get update apt-get upgrade apt-get dist-upgrade shutdown -h now

Get in the habit of running apt-get update and apt-get upgrade regularly. It's one way you keep your Ubuntu server patched and secure! apt-get dist-upgrade should be run if you see "The following packages have been kept back..." when you run apt-get upgrade. This means that some packages haven't been upgraded because they involve core, operating system-level updates that require a restart of the machine.

Configure networking on the host machine

On the host machine, run the following commands below. The first line sets up a handy environment variable you can use later. Just replace "Ubuntu 10.04 LTS" with whatever name you gave your VM when setting it up in VirtualBox. The commands below assume you haven't changed your network adapter type in VirtualBox from the default. If you have, you'll likely need to change the device name.

ubuntu_vm="Ubuntu 10.04 LTS" VBoxManage setextradata "$ubuntu_vm" "VBoxInternal/Devices/e1000/0/LUN#0/Config/guestssh/Protocol" TCP VBoxManage setextradata "$ubuntu_vm" "VBoxInternal/Devices/e1000/0/LUN#0/Config/guestssh/GuestPort" 22 VBoxManage setextradata "$ubuntu_vm" "VBoxInternal/Devices/e1000/0/LUN#0/Config/guestssh/HostPort" 2222 VBoxManage setextradata "$ubuntu_vm" "VBoxInternal/Devices/e1000/0/LUN#0/Config/guesthttp/Protocol" TCP VBoxManage setextradata "$ubuntu_vm" "VBoxInternal/Devices/e1000/0/LUN#0/Config/guesthttp/GuestPort" 80 VBoxManage setextradata "$ubuntu_vm" "VBoxInternal/Devices/e1000/0/LUN#0/Config/guesthttp/HostPort" 8888

Now, start the VM back up. You should now be able to SSH into your Ubuntu VM as follows:

ssh localhost -p 2222

Install Apache, PHP and MySQL

Now, install some generally useful packages that will be used for the rest of the process.

apt-get install build-essential git-core subversion cvs python-software-properties curl

Before we get to the web server setup, we need to change Ubuntu's package definitions a bit. Ubuntu 10.04 LTS is configured to pull PHP 5.3.x, but many Drupal 6.x contrib modules aren't compatible with PHP 5.3, so we need to downgrade to PHP 5.2.x. We'll follow some instructions from Khalid at 2bits. We'll take his Approach #3 by adding Ralph Janke's PHP 5.2 repository for Lucid and "pinning" the PHP version to 5.2, to make sure we don't inadvertantly upgrade to 5.3 (I've provided the apt preferences file in my Github repository, for easy access).

add-apt-repository ppa:txwikinger/php5.2 wget http://github.com/jrbeeman/drupal-patches/raw/master/ubuntu-10.04-apt-php-prefs.txt -O /etc/apt/preferences.d/php apt-get update

Now, we'll install the web server, PHP packages (including APC), and MySQL. Please note that you'll be prompted for a MySQL root user password. The last command below also disables some unneeded Apache modules and enables a few that are good to have for Drupal.

apt-get install apache2 php5 php5-cli php5-gd php-pear php5-dev apache2-dev apt-get install mysql-server php5-mysql a2dismod cgi autoindex a2enmod deflate expires rewrite vhost_alias pecl install apc

Configure Apache and PHP

Update PHP settings by editing both /etc/php5/apache2/php.ini and /etc/php5/cli/php.ini and setting the variables below as shown:

safe_mode = Off expose_php = Off memory_limit = 128M display_errors = Off log_errors = On
error_log = /var/log/php/php.log ; (or php_cli.log)

Update APC settings by editing /etc/php5/conf.d/apc.ini:

extension=apc.so apc.enabled=1 apc.enable_cli=1 apc.shm_segments=1 apc.shm_size=32 apc.cache_by_default=1 apc.stat=1

Create the error log files:

mkdir /var/log/php touch /var/log/php/php.log touch /var/log/php/php_cli.log chown -R www-data:www-data /var/log/php chmod -R 0755 /var/log/php

Due to the way Drupal handles URLs, in particular how it handles creating a URL to itself, we need to tell Apache to listen on port 8888. This gets around the "HTTP Request Fail" issue in the status report, among other things:

Edit /etc/apache2/ports.conf and add Listen 8888, so that the beginning of the file looks like:

NameVirtualHost *:80 Listen 80 Listen 8888

Install and configure Drush

Setup Drush and Drush Make to be used server-wide. The commands below grab the latest verison as of this writing, but you can check the Drush and Drush Make project pages to see if there are newer releases:

cd /usr/local/src wget http://ftp.drupal.org/files/projects/drush-6.x-3.3.tar.gz wget http://ftp.drupal.org/files/projects/drush_make-6.x-2.0-beta8.tar.gz tar xzf drush-6.x-3.3.tar.gz tar xzf drush_make-6.x-2.0-beta8.tar.gz mkdir /etc/drush cp /usr/local/src/drush/examples/example.drushrc.php /etc/drush/drushrc.php ln -s /usr/local/src/drush/drush /usr/local/bin/drush

Edit /etc/drush/drushrc.php to add Drush Make to include path:

$options['i'] = '/usr/local/src/drush_make';

Install Drupal

Create a database, download, and install Drupal (be sure to put a password in for the MySQL grant statement where appropriate below). I like to keep my sites in sub-directories of /var/www. These commands will prepare Apache for that working setup. I've provided a couple of files that are downloaded with wget to make this simpler, but feel free to modify them along the way if you wish.

mysql -u root -p -e "CREATE DATABASE drupal_dev; GRANT ALL PRIVILEGES ON drupal_dev.* TO [email protected] IDENTIFIED BY 'password'; FLUSH PRIVILEGES;" wget http://github.com/jrbeeman/drush-make/raw/master/drupal-demo.make -O /var/www/drupal-demo.make wget http://github.com/jrbeeman/drupal-patches/raw/master/ubuntu-drupal-demo_apache2-conf -O /etc/apache2/sites-available/drupal-demo a2dissite 000-default a2ensite drupal-demo chown -R www-data:www-data /var/www sudo -u www-data drush make /var/www/drupal-demo.make /var/www/drupal-demo sudo -u www-data cp /var/www/drupal-demo/sites/default/default.settings.php /var/www/drupal-demo/sites/default/settings.php /etc/init.d/apache2 restart

Walk through Drupal's install wizard by visiting http://localhost:8888. Once you're done, run the following Drush command to quickly enable the modules in the demo site:

cd /var/www/drupal-demo drush en -y admin \ content content_copy fieldgroup filefield imagefield nodereference \ number optionwidgets text userreference bulk_export ctools \ ctools_custom_content page_manager views_content path search devel \ features imageapi imageapi_gd imagecache imagecache_ui masquerade \ pathauto skinr strongarm token panels_mini panels_node panels \ jquery_update vertical_tabs views views_bulk_operations views_export \ views_ui fusion_core


You're done! From here, you've got a fully-functional Ubuntu virtual machine designed for developing Drupal sites.


There are some issues to work out and other tasks to add to these instructions. Any feedback on these items would be greatly appreciated.


  • Drupal reports that it can't make HTTP requests, but it can. I believe this is because we're making requests over port 8888, but Drupal thinks it's running on port 80. Not sure how to get around this, but also not sure it's really all that important for development environments.


  • TODO: Install and configure Aegir
  • TODO: Install and configure Varnish
  • TODO: Install and configure Solr


Aug 08 2010
Aug 08

As a platform, Drupal has excellent javascript support. Drupal 7 will ship with jQuery 1.4.2 and jQuery UI 1.8, which will make it even easier to build rich user interactions with Drupal.

Drupal supports aggregating javascript files to reduce the number of network connections a browser must open to load a page. It is common practice for Drupal themes to put the

Aug 01 2010
Aug 01

With CSS3 the W3C has introduced a new goodie for design on the web: Media Queries. Until then stylesheets could only be called conditionally by using media types like "print" or "screen". Media Queries extends this to being able to use certain properties as a controlling mechanism if to load a style or not.

You could specify that a stylesheet is only loaded if the browser window has a maximum width of 800px. To do so, you simply extend the value of the media-attribute by the desired attribute and value when inserting the stylesheet. To get our example to work we need to use the following HTML-Code:

As an alternative you could also write it into the stylesheet directly: @media screen and (max-width: 800px) { ... } If you're working with Drupal (which you should), you can use the regular .info file of the theme you're using: stylesheets[screen and (max-width: 800px)][] = style.css

Writing the above HTML-Code () directly into page.tpl.php would be also possible, but this is not a clean way and thus not "the Drupal way". Stylesheets should be called from the .info file and most likely your regular stylesheet is already being called from there. Media Queries in Drupal can also be called in the function drupal_add_css().

Of course this is not limited to using the width of the browser window as an attribute. E.g. there are height, width, orientation, color and resolution. All allowed attributes and the correct way of using them can be found at Media Queries (Media Features.

To get a glimpse of how it works check out this very site, undpaul.de. As soon as the browser window gets resized to a width of less than 980px, the right sidebar jumps below the main content and the header and logo get smaller. When getting below 820px width, the header gets even smaller.

Another positive side effect comes for free: when viewing the site on mobile devices, it looks much more structured, because the right sidebar blocks are no longer taking up space in the main content.

I should mention one drawback: users of browsers that do not understand CSS3 (which are Internet Explorer up to version 8, Firefox < 3.x) cannot benefit from this feature. There is a script (css3-mediaqueries.js), which enables media queries for those browsers, but we haven't tested it yet. I also do not see it as best practice to load more JavaScript for every little feature.

Jul 28 2010
Jul 28

(This is content originally posted at http://jcfiala.net/blog/2010/07/28/magic-command-invocation-drush.)

I've recently been digging into the Aegir Hosting System, both because we're starting to use it at my current NREL gig, and because I've proposed to do a session on it at DrupalCamp LA. In short, Aegir allows you to easily administer a number of Drupal sites from a common site, itself built on Drupal. It's really slick, and a lot of the functionality is built on Drush. (Also see http://drupal.org/project/drush .)

So I'm looking into how Aegir handles tasks, which are just what they sound like - nodes representing commands that Aegir fires off every minute or so from a queue - if the queue's empty then that's that, but otherwise it calls drush hosting-task #, where the # is a task node id. Wanting to know what that actually does, I looked around, found hosting.drush.inc, and discovered that it didn't have a callback.

Huh. I'd thought that Drush commands had to have a callback, but here I discover that they don't. So, I wondered, what's actually going on there? And, following the advice handed to me by Greg Knaddison when I started in Drupal, I started following the code. And here's what I found:

Generally, you want to use the callbacks on drush commands when they're fairly simple - the task is doing something basic that can be handled easily. If it's something more complex, you can skip the callback, and gain a fair amount of control over how your command is invoked, and even cleanup help if something goes south.

If a drush command doesn't have a callback, then the command info is handed off to a function called drush_invoke - you can find it in the command.inc file. (For the purposes of this, I'm going to call the command hosting-task, because that's what I was looking for when I found this out, and it's a good example.) The first thing drush_invoke does is look for an include file named after the reverse of the command name - so our hosting-task gets inverted and the dashes are converted to dots, leaving us with task.hosting.inc. It then looks around to find this file in any directory that contains a *.drush.inc file - the folks working on Aegir in this case put task.hosting.inc in the same directory as hosting.drush.inc, which makes sense. Now, there doesn't have to be an include file like this, and if Drush doesn't find one, it'll still continue to the next part. But if you've got a complex command that you're handing off to drush_invoke to handle for you, why not put it in it's own file for neatness' sake?

Continuing, after the possible file load, the drush command is turned into a base $hook by the simple expedience of changing any spaces or dashes into underscores - so for the example, we'd have a base hook of 'hosting_task' With that constructed, drush looks for functions named off of this command as follows:

  1. $hook_validate (ie, hosting_task_validate)
  2. pre_$hook (ie, pre_hosting_task)
  3. $hook (ie, hosting_task)
  4. post_$hook (ie, post_hosting_task)

And then, for each module that defines a module.drush.inc file, drush looks for a drush_$modulename_$function... which means that for the hosting module, it looks for:

  1. drush_hosting_hosting_task_validate
  2. drush_hosting_pre_hosting_task
  3. drush_hosting_hosting_task
  4. drush_hosting_post_hosting_task

If you look at task.hosting.inc, you'll see that most of these are defined - they're not actually using drush_hosting_pre_hosting_task, but that's because they're doing their preparation work in the drush_hosting_hosting_task_validate function. So, the drush_invoke happily continues along this series of commands, until it either reaches the end (oh, happiness), or one of these functions invokes drush_set_error() - in which case the whole stack of commands reverses and runs backwards, and drush_invoke sees if there's a function named exactly the same, only with '_rollback' appended to the name. (For our example, there is a drush_hosting_hosting_task_rollback() defined in task.hosting.inc.)

A note on naming - although above we've referenced drush_hosting_hosting_task_validate and drush_hosting_hosting_task, the folks who maintain Drush recognize that these are pretty long names to have to construct, and as such they check for when one of these function names they construct starts with drush_module_module and change it over to drush_module. So, in task.hosting.inc, they really should be naming the callback functions drush_hosting_task_validate and drush_hosting_task... but for now Drush recognizes the old form and still will call them.

So to summarize what I've said so far, if you run into a Drush command without a callback, what you really should be looking for is a file named the reverse of the name in the same directory as the hook_drush_command implementation, and that file should contain the drush_module_command functions. And alternately, if you want to create a Drush command that can rollback/clean up after itself, then you want to create your commands in a reverse-order name file.

But... there's something else.

drush_invoke goes through all of the modules which define drush hooks when looking for functions to call when invoking a drush command. So, if you wanted to do extra work on hosting-task drush commands, you could create an example.drush.inc in your example.module, and then define your own drush_example_hosting_task function. Heck, you could define any of:

  1. drush_example_hosting_task_validate
  2. drush_example_pre_hosting_task
  3. drush_example_hosting_task
  4. drush_example_post_hosting_task

This is pretty exciting, as it opens up a lot of customization not only in Drush, but also in Aegir. I think as Aegir continues to mature, we're going to start seeing a bunch of modules which extend it in various ways.

Jul 22 2010
Jul 22

The next couple of months are going to be a crazy ride. I will be visiting at least 7 countries, speaking on 8 or more days in a 5 week period. The talks will be focused on Drupal and Aegir. My schedule is below.

Horizontally Scaling Drupal - Melbourne

On 7 August I’ll be running a 1 day workshop around the theme of horizontally scaling Drupal. The content is built on the knowledge I developed building, deploying and managing around 2100 sites for a client. This event has very limited capacity and has almost sold out.

DrupalCon - Denmark

Denmark is hosting the European leg of DrupalCon this year. I will be attending the full conference. I won’t be presenting, but I will be getting involved with some of the BoFs. I had a ball at DrupalCon San Francisco earlier in the year.

Efficiently Managing Many Drupal Sites - Slovakia

After spending a couple of days recovering from DrupalCon, I’ll be teaming up with the crew at Sven Creative in Bratslavia, to run a 2 day intensive workshop on horizontally scaling Drupal and development workflows. For more information check out the workshop website.

Free Software Balkans - Albania

On the weekend of 11-12 September, the inaugural Free Software Balkans Conference will be held at the University of Vlore, Albania. I’ll be there speaking about Drupal and Aegir. In addition to this I will be running half day build your first Drupal site workshops around the country. The dates and locations for the workshops are still being finalised.

OSI Days - India

On my way back to Australia I will be taking a side trip to Chennai, via Delhi, for OSI Days 2010, Asia’s largest open source conference. I will be presenting sessions on Aegir and Drupal. This looks like it will be a huge event.

Other Events

I’ve launched a new site workshops.davehall.com.au to list my training and speaking engagements. As dates are locked in I’ll be adding them to the site.

If you would like to meet with me while I’m on the road, add me to your tripit network, follow me on identi.ca or twitter or add me to your network on LinkedIn.

Jul 07 2010
Jul 07

Alfresco wants to be a best-in-class repository for you to build your content-centric applications on top of. Interest in NOSQL repositories seems to be growing, with many large well-known sites choosing non-relational back-ends. Are Alfresco (and, more generally, nearly all ECM and WCM vendors) on a collision course with NOSQL?

First, let’s look at what Alfresco’s been up to lately. Over the last year or so, Alfresco has been shifting to a “we’re for developers” strategy in several ways:

  • Repositioning their Web Content Management offering not as a non-technical end-user tool, but as a tool for web application developers
  • Backing off of their mission to squash Microsoft SharePoint, positioning Alfresco Share instead as “good enough” collaboration. (Remember John Newton’s slide showing Microsoft as the Death Star and Alfresco as the Millenium Falcon? I think Han Solo has decided to take the fight elsewhere.)
  • Making Web Scripts, Surf, and Web Studio part of the Spring Framework.
  • Investing heavily in the Content Management Interoperability Services (CMIS) standard. The investment is far-reaching–Alfresco is an active participant in the OASIS specification itself, has historically been first-to-market with their CMIS implementation, and has multiple participants in CMIS-related open source projects such as Apache Chemistry.

They’ve also been making changes to the core product to make it more scalable (“Internet-scalable” is the stated goal). At a high level, they are disaggregating major Alfresco sub-systems so they can be scaled independently and in some cases removing bottlenecks present in the core infrastructure. Here are a few examples. Some of these are in progress and others are still on the roadmap:

  • Migrating away from Hibernate, which Alfresco Engineers say is currently a limiting factor
  • Switching from “Lucene for everything” to “Lucene for full-text and SQL for metadata search”
  • Making Lucene a separate search server process (presumably clusterable)
  • Making OpenOffice, which is used for document transformations, clusterable
  • Hiring Tom Baeyens (JBoss jBPM founder) and starting the Activiti BPMN project (one of their goals is “cloud scalability from the ground, up”)

So for Alfresco it is all about being an internet-scalable repository that is standards-compliant and has a rich toolset that makes it easy for you to use Alfresco as the back-end of your content-centric applications. Hold that thought for a few minutes while we turn our attention to NOSQL for a moment. Then, like a great rug, I’ll tie the whole room together.

NOSQL Stores

A NOSQL (“Not Only SQL”) store is a repository that does not use a relational database for persistence. There are many different flavors (document-oriented, key-value, tabular), and a number of different implementations. I’ll refer mostly to MongoDB and CouchDB in this post, which are two examples of document-oriented stores. In general, NOSQL stores are:

  • Schema-less. Need to add an “author” field to your “article”? Just add it–it’s as easy as setting a property value. The repository doesn’t care that the other articles in your repository don’t have an author field. The repository doesn’t know what an “article” is, for that matter.
  • Eventually consistent instead of guaranteed consistent. At some point, all replicas in a given cluster will be fully up-to-date. If a replica can’t get up-to-date, it will remove itself from the cluster.
  • Easily replicate-able. It’s very easy to instantiate new server nodes and replicate data between them and, in some cases, to horizontally partition the same database across multiple physical nodes (“sharding”).
  • Extremely scalable. These repositories are built for horizontal scaling so you can add as many nodes as you need. See the previous two points.

NOSQL repositories are used in some extremely large implementations (Digg, Facebook, Twitter, Reddit, Shutterfly, Etsy, Foursquare, etc.) for a variety of purposes. But it’s important to note that you don’t have to be a Facebook or a Twitter to realize benefits from this type of back-end. And, although the examples I’ve listed are all consumer-facing, huge-volume web sites, traditional companies are already using these technologies in-house. I should also note that for some of these projects, scaling down is just as important as scaling up–the CouchDB founders talk about running Couch repositories in browsers, cell phones, or other devices.

If you don’t believe this has application inside the firewall, go back in time to the explosive growth of Lotus Notes and Lotus Domino. The Lotus Notes NSF store has similar characteristics to document-centric NOSQL repositories. In fact, Damien Katz, the founder of CouchDB, used to work for Iris Associates, the creators of Lotus Notes. One of the reasons Notes took off was that business users could create form-based applications without involving IT or DBAs. Notes servers could also replicate with each other which made data highly-available, even on networks with high latency and/or low bandwidth between server nodes.

Alfresco & NOSQL

Unlike a full ECM platform like Alfresco, NOSQL repositories are just that–repositories. Like a relational database, there are client tools, API’s, and drivers to manage the data in a NOSQL repository and perform administrative tasks, but it’s up to you to build the business application around it. Setting up a standalone NOSQL repository for a business user and telling them to start managing their content would be like sticking them in front of MySQL and doing the same. But business apps with NOSQL back-ends are being built. For ECM, projects are already underway that integrate existing platforms with these repositories (See the DrupalCon presentation, “MongoDB – Humongous Drupal“, for one example) and entirely new CMS apps have been built specifically to take advantage of NOSQL repositories.

What about Alfresco? People are using Alfresco and NOSQL repositories together already. Peter Monks, together with others, has created a couple of open source projects that extend Alfresco WCM’s deployment mechanism to use CouchDB and MongoDB as endpoints (here and here).

I recently finished up a project for a Metaversant client in which we used Alfresco DM to create, tag, secure, and route content for approval. Once approved, some custom Java actions deploy metadata to MongoDB and files to buckets on Amazon S3. The front-end presentation tier then queries MongoDB for content chunks and metadata and serves up files directly from Amazon S3 or Amazon’s CloudFront CDN as necessary.

In these examples, Alfresco is essentially being used as a front-end to the NOSQL repository. This gives you the scalability and replication features on the Content Delivery tier with workflow, check-in/check-out, an explicit content model, tagging, versioning, and other typical content management features on the Content Management tier.

But why shouldn’t the Content Management tier benefit from the scalability and replication capabilities of a NOSQL repository? And why can’t a NOSQL repository have an end-user focused user interface with integrated workflow, a form service, and other traditional DM/CMS/WCM functionality? It should, it can and they will. NOSQL-native CMS apps will be developed (some already exist). And existing CMS’s will evolve to take advantage of NOSQL back-ends in some form or fashion, similar to the Drupal-on-Mongo example cited earlier.

What does this mean for Alfresco and ECM architecture in general?

Where does that leave Alfresco? It seems their positioning as a developer-focused, “Internet-scale” repository ultimately leads to them competing directly against NOSQL repositories for certain types of applications. The challenge for Alfresco and other ECM players is whether or not they can achieve the kind of scale and replication capabilities NOSQL repositories offer today before NOSQL can catch up with a new breed of Content Management solutions built expressly for a world in which content is everywhere, user and data volumes are huge and unpredictable, and servers come and go automatically as needed to keep up with demand.

If Alfresco and the overwhelming majority of the rest of today’s CMS vendors are able to meet that challenge with their current relational-backed stores, NOSQL simply becomes an implementation choice for CMS vendors. If, however, it turns out that being backed by a NOSQL repository is a requirement for a modern, Internet-scale CMS, we may see a whole new line-up of players in the CMS space before long.

What do you think? Does the fundamental architecture prevalent in today’s CMS offerings have what it takes to manage the web content in an increasingly cloud-based world? Will we see an explosion of NOSQL-native CMS applications and, if so, will those displace today’s relational vendors or will the two live side-by-side, potentially with buyers not even knowing or caring what choice the vendor has made with regard to how the underlying data is persisted?

Jul 03 2010
Jul 03

Here’s the story in one (code) line:

find ./ -name *.* -type f -exec s -i "s/group/og/g" '{}' \;

For the humans amongst us, I’ll explain. As part of the rewrite of Organic groups to Drupal 7, I thought that the name also deserves a rename – to follow Drupal’s naming standards. Since there weren’t enough votes in the poll in g.d.o I’ve decided _not to go with the change. OG module will keep its name - although in the UI we will use “Group” (the same way as node is refereed to as content).

I’ll commit all the changes that are currently in github back to OG’s cvs, after Add entity key label will land.

Yet another advantage of #d7cx - decisions can be undone.

Jun 30 2010
Jun 30

If you haven’t read Roger Lopez Ajax without Javascript take a 5 minutes break and do it. If you are not a developer and all this code makes you frightened then you are excused. This post will also have a little code, but take a big breath and you’ll see how easy it is to Ajaxify your Panels!

  1. Download this feature and the related modules drush dl ctools panels views && drush en page_manager panels views_content views_ui story_list php -y
  2. Add a few story nodes (title and body), or use Devel generate module to do it for you
  3. Navigate to /story-list and you should see a list of the last 10 stories on the left and the body of the first story on the right
  4. Click on any of the titles and notice how the body text changes, without any page load. Hooray!

Lets go over the things we did to achieve this behavior:

  1. We have created a View that has two different displays. The "Story list" shows a list of 10 stories. The fields of this display are the node ID which is "excluded from display" and the node title. In the node title configuration we disabled the "Link field to its node", and we craft our own link so it will link to the new Panels page we created. We also add ```ctool-use-ajax``` css class, which will ajaxify those links
  2. In the story list view we add one line of PHP in the header - ```ctools_add_js('ajax-responder');``` This line will make sure that "somebody" is listening to our ajax links
  3. In the panel page, we add to the right pane a generic css class ```ajax-result-pane```. When the ajax command will want to replace the existing text with the new text it will look for this class
  4. Next we have our custom code, which is in the ```.module``` file. I won't go over every line of code, since it is well documented. Even if you are not a developer it should be pretty clear from the comments what needs to be replaced in order to re-use the code for your own needs
Jun 28 2010
Jun 28

Apache Solr is an excellent full text index search engine based on Lucene. Solr is increasingly being used in the Drupal community for search. I use it for search for a lot of my projects. Recently Steve Edwards at Drupal Connect blogged about setting up a mutli core Solr server on Ubuntu 9.10 (aka Karmic). Ubuntu 10.04LTS was released a couple of months ago and it makes the process a bit easier, as Apache Solr 1.4 has been packaged. An additional advantage of using 10.04LTS is that it is supported until April 2015, whereas support for 9.10 ends in 10 months - April 2011.

As an added bonus in this howto you will be able to auto provision solr cores just by calling the right URL.

In this tutorial I will be using Jetty rather than tomcat which some tutorials recommend, as Jetty performs well and generally uses less resources.

Install Solr and Jetty

Installing jetty and Solr just requires a single command: sudo apt-get install solr-jetty openjdk-6-jdk.

This will pull down Solr and all of the dependencies, which can be alot if you have a very stripped down basic server.

Configuring Jetty

Configuring Jetty is very straight forward. First we backup the existing /etc/default/jetty file by running sudo cp -a /etc/default/jetty /etc/default/jetty.bak

Then change your /etc/default/jetty to be like this (the changes are highlighted):

# Defaults for jetty see /etc/init.d/jetty for more

# change to 0 to allow Jetty to start

# change to 'no' or uncomment to use the default setting in /etc/default/rcS

# Run Jetty as this user ID (default: jetty)
# Set this to an empty string to prevent Jetty from starting automatically

# Listen to connections from this network host (leave empty to accept all connections)
#Uncomment to restrict access to localhost
#JETTY_HOST=$(uname -n)

# The network port used by Jetty

# Timeout in seconds for the shutdown of all webapps

# Additional arguments to pass to Jetty

# Extra options to pass to the JVM
#JAVA_OPTIONS="-Xmx256m -Djava.awt.headless=true"

# Home of Java installation.

# The first existing directory is used for JAVA_HOME (if JAVA_HOME is not
# defined in /etc/default/jetty). Should contain a list of space separated directories.
#JDK_DIRS="/usr/lib/jvm/default-java /usr/lib/jvm/java-6-sun"

# Java compiler to use for translating JavaServer Pages (JSPs). You can use all
# compilers that are accepted by Ant's build.compiler property.

# Jetty uses a directory to store temporary files like unpacked webapps

# Jetty uses a config file to setup its boot classpath

# Default for number of days to keep old log files in /var/log/jetty/

If you don’t include the JETTY_HOST entry Jetty will only bind to the local loopback interface, which is all you need if your drupal webserver is running on the same machine. If you set the JETTY_HOST make sure you configure your firewall to restrict access to the Solr server.

Configuring Solr

I am assuming you have already installed the Apache Solr module for Drupal somewhere. If you haven’t, do that now, as you will need some config files which ship with it.

First we enable the multicore support in Solr by creating a file called /usr/share/solr/solr.xml with the following contents:

persistent="true" sharedLib="lib">
  adminPath="/admin/cores" shareSchema="true" adminHandler="au.com.davehall.solr.plugins.SolrCoreAdminHandler">

You need to make sure the file is owned by the jetty user if you want it to be dynamically updated, otherwise change persistent="true" to persistent="false", don’t include the adminHandler attribute and don’t run the commands below. Also if you want to auto provision cores you will need to download the jar file attached to this post and drop it into the /usr/share/solr/lib directory (which you’ll need to create).

sudo chown jetty:jetty /usr/share/solr
sudo chown jetty:jetty /usr/share/solr/solr.xml
sudo chmod 640 /usr/share/solr/solr.xml
sudo mkdir /usr/share/solr/cores
sudo chown jetty:jetty /usr/share/solr/cores

To keep your configuration centralised, symlink the file from /usr/share/solr to /etc/solr. Do this by calling sudo ln -s /usr/share/solr/solr.xml /etc/solr/. Don’t do it the other way, Solr will ignore the symlink.

Solr needs to be configured for Drupal. First we backup the existing config file, just in case, like so:

sudo mv /etc/solr/conf/schema.xml /etc/solr/conf/schema.orig.xml
sudo mv /etc/solr/conf/solrconfig.xml /etc/solr/conf/solrconfig.orig.xml

Now we copy the Drupal Solr config files from where you installed the module by running

sudo cp /path/to/drupal-install/sites/all/modules/contrib/apachesolr/{schema,solrconfig}.xml /etc/solr/conf/

Solr needs the path to exist for each core’s data files, so we create them with the following commands:

sudo mkdir -p /var/lib/solr/cores/{,subdomain_}example_com/{data,conf}
sudo chown -R jetty:jetty /var/lib/solr/cores/{,subdomain_}example_com

Each of the cores need their own configuration files. We could implement some hacks to use a common set of configuration files, but that will make life more difficult if we ever have to migrate some of cores. Just copy the common configuration for all the cores:

sudo bash -c 'for core in /var/lib/solr/cores/*; do cp -a /etc/solr/conf/ $core/; done'

If everything is configured correctly, we should just be able to start Jetty like so:

sudo /etc/init.d/jetty start

If you visit http://solr.example.com:8080/solr/admin/cores?action=STATUS you should get some xml that looks something like this:


If you get the above output everything is working properly

If you enabled auto provisioning of Solr cores, you should now be able to create your first core. Point your browser at http://solr.example.com:8080/solr/admin/cores?action=CREATE&name=test1&instanceDir=test1 If it works you should get output similar to the following:


I would recommend using identifiable names for your cores, so for davehall.com.au I would call the core, “davehall_com_au” so I can easily find it later on.

Security Note: As anyone who can access your server can now provision solr cores, make sure you restrict access to port 8080 to only allow access from trusted IP addresses.

For more information on the commands available, refer to the Solr Core Admin API documenation on the Solr wik.

Next in this series will be how to use this auto provisioning setup to allow aegir to provision Solr cores as sites are created.

May 04 2010
May 04

I'm working on a project to convert a big ASP website into Drupal. On Windows OSes there is not really a distinction between upper and lower case characters in filenames. At first I thought to just leave the capitals, but on web pages links were sometimes with capitals and sometimes lowercase. So I added some stuff to the Apache configuration, usually inside the VirtualHost directive (this does not work in .htaccess):

        RewriteEngine on
        RewriteMap lc int:tolower
        RewriteCond %{REQUEST_URI} [A-Z]
        RewriteRule (.*) ${lc:$1} [R=301,L]

But that wasn't all. For the project I'm parsing thousands of ASP files and the plan is to do this everyday while the existing website is updated. We're rsyncing files to be parsed, and the recursively rename to lowercase script I found is nice but it's not very efficient to copy and rename almost 3 GB everyday. I wrote a little Python script in the train today to create lowercase symbolic links to file and directory names with uppercase letters. The hardest part was to properly change directories - it's important to change into the directory the symlink is created but at the end of an os.walk it's necessary to get back to the current working directory.

I'm sure it can be useful to other people dealing with similar issues...

#!/usr/bin/env python

Recursively creates lower case symlinks to filenames with uppercase letters.

Created by Guaka in 2010, consider this public domain, copy and re-use freely.

import os

def lowlink(path = '.'):
    cwd = os.getcwd()  # os.walk can't handle path changes very well 
    for root, dirs, files in os.walk(path):
        # change directory for symlink creation
        os.chdir(os.path.join(cwd, root))
        print root
        for name in files + dirs:
            lowname = name.lower()
            if name != lowname and not os.path.exists(lowname):
                os.symlink(name, lowname)
        os.chdir(cwd) # restore path for os.walk

my working setup
Apr 29 2010
Apr 29

DrutNet is a .NET API to create client applications that connects to a Drupal site, and allow file upload, node save/load, view get and more.

Introduction I’ve created this simple API to connect Drupal with .NET applications easily and quickly, this API was based on an API that I wrote for one of our projects, for this project we had to create a few client application to upload files, connect to desktop application and update the content. I used two different interfaces to cover all my needs, cURL - to upload files; and Services module - to create/ update nodes.

Features Snapshot DrutNet API has a Services class:

  • Services.Login - Login to Drupal
  • Services.NodeGet - Load a node
  • Services.UserGet - Load a user
  • Services.NodeSave - Save a node

To upload files using the API use the CURL class:

  • Curl.Login - Login to Drupal with cURL, which is required in order to uplaod a file. This login is _not the same as the Services login
  • Curl.UploadFile - Upload a file to a CCK file/ image field. The "File form" module provided in the ```/Drupal Module``` folder must be enabled on the Drupal site

Source The source code is stored under GitHub (we didn’t publish it in Drupal as apparently it against some the CVS guidelines).

Example In the source there is a sample project, that demonstrates the use of the API to load/ save a node, and to upload a file. To test the API follow the instructions bellow (no programing or compiling required when using the):

  1. Place both Drupal modules under '/Drupal Module' in your Drupal installation (e.g. under ```sites/all/modules```): - DrutNet sample module - The module creates a ```DrutNet smaple``` content type to test the system with the DrutNETSample - File form - This module is required for file upload with cURL
  2. Download and enable the required modules ``` drush dl cck views features filefield services ```
  3. Compile the sample project Or use the already compiled program in ```/Dlls/DrutNETSample.exe```
  4. Insert your username password to Drupal and the Drupal site URL
  5. Click on "Login to services", and then click "Login to cURL".
  6. Update an existing node by indicating the node ID, loading it, changing the text and "Save" it.
  7. To test file upload, switch to the Upload tab, choose a file and fill the node ID, CCK field name to attach the file to (in our example we use ```field_file```), and hit the Upload Button

For features or bug report use GitHub project page

Apr 28 2010
Apr 28

We recently received a report by "ZeroDayScan", about a "Full path disclosure bug in Drupal 6.16".

You can read the story @ http://blog.zerodayscan.com/2010/04/full-path-disclosure-bug-in-drupal-6.... As my short comment was removed from the post, I have to resort to a blogpost. My apologies for polluting the Planet.

Summary of the issue: If you set error reporting to the default value "Write errors to the log and to the screen", the installation path is displayed on the ...*drumroll*... screen.

Which is of course the point.

Calling the setting a "workaround", the default a "bug" and a "vulnerability" is either idiocy, or insincere. Now that comments were removed, we know. Insincere and at the same time a great way to highlight the impotence of the ZeroDayScan scanner.

My last message to ZeroDayScan: If there's an SQL injection on a Drupal site; you can simply take over the site as uid 1 (root); no need to find out the full path via an obscure error message.

Apr 26 2010
Apr 26

UPDATE: Since writing this post ninesixty theme has advanced. I am now using it as my base theme, and create a subtheme. I no longer use Zen.

Zen is my first favorite base theme. Ninesixty is the other. The following post will show how we can enjoy both of them - How we can have a “Zen-960” theme _done correctly.

As always, lets first understand _why we want to combine those two themes. JohnAlibn’s Zen is a great starter theme - if you need a list of features, just head to the project page, you won’t be disappointed. dvessel’s Ninesixty takes the power of grid 960 -that we really love as it allows us to spend less time banging our heads on CSS - and adapts it to Drupal.

The way that I look at it - Zen should be doing the job of defining the page _elements (how fonts will look, lists, tabs, etc’) and defining their RTL equivalent. Ninesixty on the other hand should be doing the job of defining the page _layout.

So what is the problem? Well, according to Drupal I’m too griddy! I want my theme to have two base themes - and that’s currently not possible. Ok, so why not just download zen_ninesixty theme (a.k.a Zen-960) and go on with my life?

Well, I downloaded Zen-960. In fact I’ve started porting it to use Zen’s 2.x version, and pretty quickly I understood something wasn’t right. Since I can have only a single base theme, Zen-960 was copying lots of Ninexisty files. Code duplication is a good sign for bad things&mldr; I’ve come up with a simple work-around that shrank Zen-960 considerably and _completely removed any code duplication.

The idea in short is two have the following themes hierarchy:

  1. Zen - Base theme –2) Zen starter - That’s how we renamed Zen’s STARTERKIT —-3) Ninesixty - We’ll make it a subtheme of Zen starter ——4) Zen ninesixty - Our theme that we can directly edit

I will not cover the process of installation in detail, as this can be read in the README.txt of the Zen-960 5.x version, but I will point out the “trick” that made it all happen. We make Ninesixty a subtheme of Zen starter, manually or or via code in a custom module (In Drupal 7 this will not be needed as themes can implement alter functions):

* Implementation of hook_system_info_alter()
* Add Zen starter theme as the base theme of Ninesixty theme.
function foo_system_info_alter(&$info, $file) {
  if ($file->name == 'ninesixty') {
    $info['base theme'] = 'zen_starter';

So simple it almost makes this whole blog post seem trivial, doesn’t it? And indeed the above lines made sure that the only things left for Zen-960 to take care of are:

  1. Disable’s Ninesixty reset.css and test.css and Zen’s layout-fixed/liquid.css - As I said before, Zen is in-charge of defining the elements and Ninesixty the layout.
  2. Provide a page.tpl which is Zen’s page.tpl sprinkled with 960’s grid classes - as a reference on how to use 960’s grids.
The message area with the yellow background is defined by Zen.On mouse hover (and 960 debug is on) the 16 columns grid appear.

To conclude, our gain here apart of enjoying the Zen and Ninesixty mix:

  1. Zen-960 doesn’t need to continue “chasing” Zen and Ninesixty development
  2. No code duplication
  3. Zen-960 became much much smaller and it’s doing it in a better “Drupal way”.

Now we can move things like 960 based Views row style template override or Panels layout to Ninesixty where, in my opinion, they belong - as they define layout.

Apr 19 2010
Apr 19

© Copyright 1999-2021 Baheyeldin.com. All rights reserved.
You can use our content under the Terms of Use.
All posted articles and comments are copyright by their owner, and reflect their own views and opinions, which may not necessarily be consistent with the views and opinions of the owners of the Baheyeldin.com.
Web site developed by 2bits.com.

Apr 17 2010
Apr 17

My experience themeing Drupal, like most of my coding skills, have been developed by digging up useful resources online and some trail and error. I have an interest in graphic design, but never really studied it. I can turn out sites which look good, but my “designs” don’t have the polish of a professionally designed site. I own quite a few (dead tree) books on development and project management. Generally I like to read when I am sick of sitting in front of a screen. The only ebooks I consider reading are short ones.

Emma Jane Hogbin offered her Drupal theming ebook Theming Drupal: A First Timer’s Guide to her mailing list subscribers for free. I am not a big fan of vendor mailing lists, most of the time I scan the messages and hit delete before the bottom. In the case of Emma, rumour has it that it is really worthwhile to subscribe to her list - especially if you are a designer interested in themeing Drupal. Emma also offered free copies of her ebook to those who begged, so I subscribed and I begged.

The first thing I noticed about the book was the ducks on the front cover, I’m a sucker for cute animal pics. The ebook is derived from Emma’s training courses and the book she coauthored with Konstantin Kaefer, Front End Drupal. Readers are assumed to have some experience with HTML, CSS and PHP. The book is pitched at designers and programmers who want to get into building themes for Drupal.

The reader is walked through building a complete Drupal theme. The writing is detailed and includes loads of references for obtaining additional information. It covers building a page theme, content type specific themeing and the various base themes available for Druapl. The book is a very useful resource for anyone working on a Drupal theme.

Although I have themed quite a few Drupal sites, Emma’s guide taught me a few things. The book is a good read for anyone who wants to improve their knowledge of Drupal themeing. Now to finish reading Front End Drupal &mldr;

Apr 14 2010
Apr 14

The following post will cover how to create dynamic landing pages. First lets define our mission:

Allow easily creating landing pages, with different content. The layout should be a header and footer which are always the same, and the main-content should be three columns layout, with dynamic content.

Before we go too technical, let’s translate the task into plain English in order to solve our task.

The layout should be a header and footer which are always the same

Or we can say it differently - don’t show the sidebars. A quick and dirty way of doing it, will be overriding page.tpl and remove the printing of the sidebars.

...three columns layout...

That’s easy with Panel’s three column layout (or we can create our own layout using 960).

...with dynamic content.

Dynamic content - that sounds like a job for Views. We can have a content type, that will have cck fields that describe the location of it (e.g. left, middle), and the page it should appear (e.g. /landing-page/foo). Views will get the right nodes for us.

Ok, now we know how we want to implement it, let’s get our hands dirty (or download the example module, and skip to 7).

  1. Download and enable necessary modules: ``` drush dl cck views ctools panels drush en optionwidgets text views_ui ctools _panels page_manager views_content ```
  2. Starting from the lowest level, we'll create a new content type called "Landing page element" with CCK fields - select list for the "Location" and a textfield for the "Page ID"
  3. Create a View that shows the full nodes, filtered by node type, that gets two arguments - the "Location" and the "Page ID"
  4. Add a new display of "Content pane" type. This display type is what ties Views to Panels in a way that allows us to define how the View is going to get its arguments
  5. Set the Page ID argument to be taken from the panel argument - or in other words, if the url will be landing-page/foo then foo is our page ID. The Location argument, on the other hand, shouldn't be taken from the URL - it should be set in the Pane configuration
  6. Create a panel page in the path ```landing-page``` with a three column layout, and in the content add our view to each of the columns. Every time the "Location" argument will change according to the column the View is added to
  7. Next, in our theme to copy page.tpl.php to page-landing-page.tpl.php, and the printing of the sidebars
  8. Optional; copy node.tpl.php to node-view-landing_page.tpl.php and delete the printing of the node title
  9. Optional; In admin/build/themes/settings uncheck "Display post information" from our new content type
  10. Now, all that is left to do, is to add three Landing page elements content, with the same page ID (e.g. `gizra`), and with different locations
  11. Navigate to landing-pages/gizra and see your landing page!

Another small note about using Panels, Views and nodes together. Although Panels allows us to add an existing content, I normally prefer to use a View that will return that node. Why? Because most of the sites I work on are multilangual, and if I hardcode the node ID then the users might see a node in the wrong language. View on the other hand can make sure the node the users see is in their language.

Apr 09 2010
Apr 09

Today I purchased a Motorola DEXT (aka Cliq) from Optus. Overall I like it. It feels more polished than the Nokia N97 which I bought last year. The range of apps is good. Even though the phone only ships with Android 1.6, 2.1 for the DEXT is due in Q3 2010.

The apps seem to run nice and fast. The responsive touch screen is bright and clear. I am yet to try to make a call on it from home, but the 3G data seems as fast as my Telstra 3G service, so the signal should be OK.

The keyboard is very functional, albeit cramped with my fat thumbs. The home screen is a little cluttered for my liking too, but it won’t take much to clean that up. I will miss my funambol sync, which is only available for Android 2.x.

I started writing this post using the Drupal Editor for Android app, which is pretty nice. The GPL app uses the XML-RPC and Drupal core’s Blog API module. Overall it feels like a stripped down version of Bilbo/Blogilo. Drupal Editor is an example of an app which does one thing and does it simply, but well. The only thing I haven’t liked about it was when originally writing this post, I bumped the save button and published an incomplete and poorly written post. Next time I will untick the publish checkbox until I am ready to really publish it.

I would still like a HTC Desire, but Telstra is only offering them on a $65 plan with no value. The Nokia N900 was off my list, due to the USB port of death and Nokia’s spam policies. The Nexus One was on the list too, but the lack of a local warranty was a concern.


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