Organizing Features for Complex Drupal Sites
We build Drupal sites with a combination of site code and the settings that Drupal stores in the database. Settings are easy for someone with no coding experience to change; but we can't track setting changes in the database as easily as we can track changes in code.
Drupal’s Features module is the most widely adopted solution in Drupal 7 for storing settings as version-controlled configuration in code. Like with most things Drupal, there isn’t just one approach to configuration in code: a few Aten folks have been working on another approach called CINC.
If you do decide to use the Features module, you’ll quickly learn there isn’t a single way of creating features. Drupal Kit provides some guidelines, but structuring and organizing Features-created modules is largely left up to the developer. Things can quickly get unwieldy on a complex site with multiple developers and many Features. In cases where Features is a project requirement, we’ve created a process that has worked well for us.
Be consistent with Features naming conventions
Our Feature names follow this convention: [projectshortname][summary][package_name]_feature
- [projectshortname] This three-character code is decided at the beginning of a project and keeps the custom module and feature names unique to the project.
- [summary] This is a super-short summary of the specifics of the feature.
- [package_name] This should closely follow the package naming convention set for the project. Keep reading to learn more about package names.
- feature This lets others know that this module was created by Features and also helps keep the module name unique.
Examples in practice
- Page content type - abc_page_entity_feature
- Image style definitions - abc_image_styles_config_feature
- Blog View - abc_blog_views_feature
Categorize Features by providing a package name
When creating a new Feature, you can specify a package name. This is the same as defining “package = [something]” in a custom module .info file. The Package name groups your feature on the Features list page and the overall modules page. Being consistent with package names makes it easier for other developers and clients to find available features. We suggest nailing down package names at the beginning of a project. Our package names typically look something like this:
- [projectshortname] Configuration (image styles, text formats, search settings, various module settings)
- [projectshortname] Entity (content types, fields, field collections, taxonomies, etc.)
- [projectshortname] Views (views defined by views module)
- [projectshortname] Page (page manager & panels)
Create a directory structure for modules created by Features
Our typical modules directory (sites/all/modules) is structured like this:
- contrib (modules downloaded from Drupal.org)
- custom (modules that aren’t contrib and specific to the project)
- features (modules created by Features)
- patched (patched contrib modules)
The Features directory (sites/all/modules/features) is then broken down a bit further to make it easier to find what you need. We try to make this mirror package names as much as possible.
- features
- configuration
- entity
- content_type
- field_collection
- shared
- taxonomy
- page
- views
Limit cross-Feature dependencies
It is normal for a Feature to be dependent on other Drupal modules. For example, a content type Feature will be dependent on the Field Group module if using field groups. When creating content type Features, fields used by the content type are tightly coupled with each feature. The quickest way to a cross-Feature dependency is by creating two content type Features that have several shared fields (e.g. body, tags). Content Type One may contain the field base for the body field. Content Type Two also uses the body and now has a dependency on Content Type One.
Cross-Feature dependencies make it hard to have Features that are truly independent and reusable across projects. Our way around this is being very intentional about when we use shared fields and adding them in a completely different Feature. We call this Feature “Shared Field Base”. This shared Feature allows Content Type One and Content Type Two to be completely independent of one another.
At the end of the day, the important thing is to pick an approach and stick with it throughout the project. We’ve created a process that works well for us, but there are other approaches. How does your approach differ from ours? What other tips do you have for creating features and keeping them organized? Are you excited about Drupal 8’s plans for configuration in code?