Features Part 1 - A simple feature
I first heard about features at DrupalCon DC and while it seemed like a nice idea, I couldn't really see how it could be practical to someone who can already write their own modules. Of course, I thought exactly the same of views when I first learned of it too.
If you build Drupal sites and you've never built a feature before, it's about time you gave it a go! This post will walk you through what a feature is and how to go about building one. In a later post I'll show you how to make your feature re-usable and why it's important.
A "feature" is simply a collection of drupal objects wrapped up into a module. Most of my features contains views, content types, permissions, image styles (imagecache presets in D6), etc. One of the goals of features was to provide a way to move database configuration into code, which also has the side effect of allowing you track any changes through your favorite revision control tool. While technically a feature is pretty much as simple as that, it becomes a very powerful tool when it comes to building Drupal platforms, re-usability between sites, and the dev -> staging -> production workflow. This concept is so important that there's even a major Drupal 8 initiative in the works with heyrocker behind it: http://groups.drupal.org/node/134569.
A common need for most websites these days is a simple blog. I've built a blog for websites at least a dozen times. The concept is simple enough and it only takes about an hour or two to set one up if you've done it before (not necessarily including theming work), but if you have a re-usable blog feature you'd save yourself that hour or two for every new site. If you bill out at $100/h, that can add up to some real money pretty fast.
Step 1: The prerequisites:
Starting with a fresh D7 "minimal" site install is probably best so you don't include settings from other parts of the site you don't intend to. Download and install a few standard modules that you'll want for the feature:
Next you'll need the features "toolkit" that will consist of a number of modules necessary for exporting various parts of our site. Download and install the following modules:
- Features - This provides the core UI and functionality for creating features.
- Strongarm - Strongarm, though it has other uses, in this case it will primarily allow us to export settings from the variables table into your features.
- Context - Contexts is a bit more difficult to explain, but for our purposes, we'll be using it to allow us to export the block layout among other things.
- Diff - This allows you to easily compare changes in your features as you're working on your site.
As you get into building features, you'll find you need to change the way you deal with some parts of your site build. One of the bigger changes is how you handle blocks. Because the default Drupal block system is not exportable you need to use a different solution. This is where contexts and boxes come in. Contexts is basically an input/output system... as a block replacement tool. the input is the current 'page' (node, views listing etc), and the output is the positioning of the blocks on the page. It should all make sense in a moment :). For more background on this I strongly recommend reading Affinity Bridge's "abridged" series of posts on the topic:
- http://affinitybridge.com/blog/drupal-features-module-abridged
- http://affinitybridge.com/blog/drupal-context-module-abridged
- http://affinitybridge.com/blog/boxes-abridged
Step 2: Building a blog
This blog feature will consist of the following:
* Blog content type
* Tags vocabulary
* Blog listing view
* Recent comments block
* Recent posts block
* Notify users of new comments (ie comment_notify)
When creating CCK types for use in features, always try to create unique fields. Features need to be somewhat independent from each other and things will be much smoother if you don't try to create generic fields that can be re-used.
Add a vocabulary called "tags" or "blog tags" (again, try not to share vocabularies across features).
Create the blog content type with a body field (called blog_body) and a term reference (called blog_tags) . Note that all settings (comment, display, etc. that you add to the content type will be exported with the feature).
Create the views necessary for the blog (or download the exports attached to this post):
- A full listing of blog posts containing the most recent posts
- Page display (path of /blog)
- Views rss display (path of /blog.xml)
- Recent blog entries
- Block containing the 5 most recent entries
- New blog comments
- Block containing the 10 newest comments on the blog
Let's put the recent comments and recent posts block next to each other on the /blog listing page. We can't use the block system for this as it's not exportable, so instead we'll use contexts. Create a new context and call it "blog_blocks". Add both a Views and a Node condition and set them up accordingly. Now add a Block reaction and add the two blocks in the proper regions (or download my context export at the end of this post).
Finally, enable and configure the comment_notify module so that readers / posters will be notified when new comments are posted.
Step 3: Creating the feature
If you made it here, then awesome! We're ready to export our blog feature now. This will give us a fully functional Drupal module that we could potentially take to any site.
Browse to admin/structure/features/create to create the new feature. Be careful when naming features as you don't want to conflict with the Drupal core or contrib module namespace (i.e. Calling this feature "blog" would conflict with the blog module). Give it a name like "blog feature" or "my blog feature" or "super awesome blog". You can safely ignore the version and URL fields for now but I'll touch on that later.
Under "Edit components" select everything we just created.
- Context: blog_blocks
- Fields: node-blog-*, comment-comment_node_blog-comment_body
- Content types: Blog
- Taxonomy: Blog tags
- Permissions:
- All comment_notify permissions
- All "Node: Blog:" permissions
- All Taxonomy "Blog Tags" permissions
- Strongarm: comment_notify_*
- Views: blog_listing, recent_blog_comments
After you've completed this, you should see a listing on the right hand of the page that looks something like this:
You'll notice some items are in blue, and others black. Features automatically identifies dependencies and adds them as the blue items. For example, all of the comment and node settings for the Blog type have been automatically added from the variables table.
Download your feature and untar it to your sites/mysite.com/modules/features/ folder. On the main features page (admin/structure/features) you should see the blog feature you just created listed there. All you have to do now is enable the feature and you're done!
I'll get into managing your feature in the next post where I'll explain the state and actions columns as well as how to update your feature.
UPDATE:
I've added the full feature export to the attachments as well.
I've found a few other links to check out on this topic:
- http://developmentseed.org/blog/2009/jan/30/easy-feature-building-spaces/
- http://www.joshwaihi.com/node/4
- http://tutr.tv/t46
UPDATE 2:
I just noticed that I made a mistake in building the feature here, I forgot to add the views we created to the feature. The article and feature export has been updated to fix that now.