Ever feel like your Drupal code is becoming a disorganised mess? Most Drupal sites contain a decent number of contributed modules. Before long, you might write your own custom modules. And then you might generate Features, which are also modules. You end up with a heck of a lot of modules! You could dump them all into the modules folder, but then how will you distinguish between what is custom and what is contributed? Sure you know what your custom modules are, but you will have to search for them through that long list of all those modules. If only they could be more organised!
Organising code into relevant buckets is critical, especially as you add more and more modules to your Drupal application. After all, Drupal core is not all in the same folder! Having good organisation makes it easier to find what you need. It makes it easier to know what can be directly changed, and what needs to be upgraded from drupal.org.
I have seen a variety of different approaches and strategies to organising code across all of the Drupal projects I have worked on and they all have their pros and cons.
Where does the modules folder live?
Your modules directory could live in sites/all or sites/example.com, or both. If you are running a multi-site install, your setup will likely look like this:
|--sites
| |-- all
| | |-- modules
| | |-- themes
| |-- example.com
| | |-- modules
| | |-- themes
In this setup, any modules and themes that can be used by any site reside in sites/all. Any modules and themes that are site specific are stored in their relevant sites folder, such as sites/example.com.
If you run a single site on a single instance of Drupal, your structure will be simplified. You only need one modules folder and one themes folder. You still may elect to have a site specific folder, which is useful if you add a second site at a later date.
The directory structure with all contrib and custom modules and themes in sites/all is as follows:
|--sites
| |-- all
| | |-- modules
| | |-- themes
It is important to note that the modules folder in sites is for contributed and custom modules only. Core modules reside in the modules folder in the root of the Drupal installation. Core modules should not be touched and you should not add any contributed or custom modules there. Why? Because it becomes a nightmare to upgrade your Drupal code if there is not a clean separation.
Now let's talk about how to structure the modules folder itself.
Custom inside Contrib
In this option, all contributed modules are inside the modules directory. The directory called custom is in the same modules folder and all custom modules are stored in there.
|-- sites
| |-- all
| | |-- modules
| | | |-- antispam
| | | |-- custom
| | | |-- cck
This is an improvement on having all modules in sites/all (or sites/example.com) with no further structure, but it is still not ideal. When you want to work on custom code, you have to pinpoint the custom directory along side all of the contributed modules. This might not sound difficult, but when you are doing this many times per day, it becomes a pain. This approach is partial organisation, but it does not go far enough to full organisation.
Custom and Contrib
In order to solve the problem of having the custom directory mixed in with contributed modules, you can create a directory called contrib, which sits along side the custom directory. All contrib modules then reside inside the contrib directory, as the name suggests. This provides the clean separation that we desire and makes it easy to find either contrib or custom modules.
|-- sites
| |-- all
| | |-- modules
| | | |-- contrib
| | | |-- custom
Contrib, Custom, Features
Most sites over a certain size use Features to manage and deploy site building configuration. When you export a feature, all of the code is auto-generated for you. For this reason, you may consider this to be a different category to custom modules, so create a separate directory for it.
|-- sites
| |-- all
| | |-- modules
| | | |-- contrib
| | | |-- custom
| | | |-- features
I have seen this approach taken on most of the Drupal projects I have been involved in. There is one problem with this though - a feature can very quickly become a custom module. It is very common to export configuration for a particular area of functionality as a feature module, and then add custom code that belongs to the same area of functionality to the .module file of the feature. For example, you may have a feature that deals with articles which contain exported code for the article content type, an article view, image presents for articles etc. You may then implement hook_form_alter() for the article node form or some other bit of custom code. Is the module now a custom module, or is it still a feature?
Some people's approach to this is that as soon as custom code is added, the module gets moved to the custom directory. The problem with this is that if you are specifically looking for feature modules in the features folder, you will obviously not see the ones that have been moved to custom. You could argue that the separation between custom and features is a separation that is not required. After all, features are modules and they are custom, even if much of the code is auto- generated. They are still modules and should be considered first class custom modules with their rightful home being the custom directory.
Contrib, Custom, Features, Dev Tools
|-- sites
| |-- all
| | |-- modules
| | | |-- contrib
| | | |-- custom
| | | |-- dev-tools
| | | |-- features
Taking this one step further to separate out any modules that are used by developers only. These modules include the likes of devel, coder etc. You probably do not want to deploy those to the live environment, so keeping them in a separate folder makes it easier to exclude them.
Contrib, Custom, Features, Dev Tools, Migration, Patches
|-- sites
| |-- all
| | |-- modules
| | | |-- contrib
| | | |-- custom
| | | |-- dev-tools
| | | |-- features
| | | |-- patches
| | | |-- migration
No doubt you will need to patch contributed modules at some stage. You should have a directory with all the patches you have applied. It is common to put those in a folder outside of the Drupal application code, but putting it inside sites/all makes sense for contributed modules (and themes).
Another addition here is migration, which includes any migration related code.
My ideal setup
My ideal setup is to separate where there is a clear need to and a clear demarcation. Because of the fuzzy line between a feature module and a non-feature custom module, I would ideally keep feature modules in with custom modules and everything else is the same as the last step.
|-- sites
| |-- all
| | |-- modules
| | | |-- contrib
| | | |-- custom
| | | |-- dev-tools
| | | |-- patches
| | | |-- migration
Wrapping up
The approach you take to organise your modules will depend on the size and complexity of your Drupal project. But whatever approach you take, it is better to organise than to be disorganised. And it is normally easier to start off with a good directory structure from the start than to have to switch to one later. At the very least, start off separating contributed and custom modules into separate folders.