Dec 06 2017
Jay
Dec 06

Illustrations showing a person signing a document from their tablet

As more and more companies make the leap to having entirely-digital communications with their customers or clients, some things have a tendency to stay on paper.  One common thing which lags behind the rest of the digitization process is the signing of legally binding documents... but no more. Now, services such as HelloSign are able to fill this void, and thanks to the HelloSign API, Drupal websites can fully leverage that service to make this important task easier both for you and for your customers.

Why HelloSign?

One common question about eSignature services is simple: Why use one at all?

Using eSignatures can be a great time- and paper-saver compared to conventional document signing. With eSignatures, you can still print a hardcopy if you want, but it's not strictly necessary to do so... no more needing to keep a painstakingly organized file cabinet! It's also just what people have come to expect. If somebody is signing up for access to a web application, for instance, needing to print and send in a document feels archaic by comparison. For these reasons and more, the benefits of eSignatures seems clear.

But, why use a service for it? Can't you just add a checkbox to the registration page of your website that says "I agree"? Well, perhaps, but depending on your use-case that isn't always a suitable solution. Imagine, for instance, that the thing being signed is an apartment rental agreement. When somebody fills out a document like that, you want a signed PDF at the end... something for your own records, and something that the renter can refer to later to review the terms, so an eSigned document if much better than simply recording that somebody clicked a button.

Furthermore, you also need the signature to be legally binding. Unless you want to navigate all of the laws to figure out how to make an eSignature be just as binding as a physical signature, using a service that has already figured out all of those details is a fantastic solution.

At Ashday, we like HelloSign because, in addition to meeting all of these needs and having many other useful features, we can use the robust HelloSign API to integrate the eSignature process directly into websites that need it.

Interested in a smooth, hassle-free HelloSign Integration?  Request your free consultation with an Ashday Drupal expert today. 

Drupal 7 Integration: Overview

Our first HelloSign integration was with a Drupal 7 site, and with that, we created and released the initial version of our HelloSign module for Drupal. This module can be used by any Drupal 7 website to facilitate the integration of HelloSign with that site.

Since this is an integration, somebody using the module still needs to have a HelloSign account that includes access to the HelloSign API and, for the best user experience, its embedded signing feature. What this module does is help get your Drupal 7 site connected to your HelloSign account and provide some useful tools for creating and managing eSignature requests.

The way the module works is simple. Once it is enabled on your site, there will be a page available on your site to enter your HelloSign API credentials. This page also has a useful "Test Mode" option to toggle whether eSignatures on the site should be "real" or just tests, which is very useful for when you are making changes to your eSignature functionality and want to be sure that it all works before people start signing any legally binding documents.

Once the HelloSIgn connection has been established, you're ready to actually use the module. Some Drupal modules create a full-fledged user interface for interacting with them, but since eSignatures can be used for so many different things, we didn't want to make any wrong assumptions about what people would want to do with the module. As such, what this module provides is a set of useful PHP functions that greatly simplify the creation of a HelloSign integration, rather than building a whole UI that might not work for all sites.

Drupal 7 Integration: The Details

If you hire a company like Ashday to build your website, of if you have software engineers at your company, they'll be the ones using the module to create an integration with the HelloSign API. In this case, you can probably skip this section. If, on the other hand, you're writing the code yourself, then this section is for you! The module's README has more details, but this should give a good overview of the overall process for using the module to integrate with the HelloSign API.

The heart of the module is the PHP function hellosign_generate_esignature_request(). All this function needs is the location of the PDF file to be signed, the names and email addresses of everyone who should sign it, a title for the document being signed, and a subject line for any emails sent regarding the eSignature. You can also create the eSignature in either "email" or "embedded" mode; we'll use "embedded" mode, since that usually makes for a better user experience. With this information, the function connects to the HelloSign API and starts the eSignature process. Assuming that all goes well, the function returns the ID of the signature request as well as information about the individual signatures needed. The request ID can then later be used by other functions to do other things related to the eSignature, such as cancelling the request, and the signature information can be used to move on to the next step: Building a page where the user can actually sign the document.

Perhaps surprisingly, this is one of the easiest parts of the integration.  The module includes a function called hellosign_get_embed_url(); give it the ID of a particular signature that you want, and it will return the URL for an iframe which you can include on whatever page you want users to go to to sign their documents.

Now, this is a Drupal 7 module, and what would a Drupal 7 module be without hooks? This module provides a single, vital hook: hook_process_hellosign_callback().  Any implementations of this hook that you create will get called whenever HelloSign notifies the site about a signature request being updated. This way, your site can know when a document gets signed or completed, and can do anything that it needs to. Need to save a copy of the signed document to your own server? The module has that covered as well. Just use hellosign_fetch_esignature_document() to get exactly the file you need, and then save it wherever you want in the file system.

Finally, if you need other, more advanced features of the HelloSign API, the module ultimately uses the HelloSign PHP SDK, so you can leverage anything you need from that even if the Drupal module doesn't specifically include functions for it. In theory, you could even create a HelloSign integration using just the SDK, but the Drupal module handles many common eSignature needs without ever needing to delve into a much more complicated utility like the SDK.

What's Next: Drupal 8

Of course, at this point, Drupal 7 is old news, and Drupal 8 is what all the cool kids are talking about. Well, don't worry: We're currently working on a new version of our HelloSign module for use on Drupal 8 sites. We've been using Drupal 8 for more than two years now (since before it's first official release!) and at this point we're pretty comfortable with the Drupal 8 way of doing things, so it's high time we brought the HelloSign module up to date. Since Drupal 8 is a much more robust and object-oriented system than Drupal 7, we're fully leveraging that to improve the structure of the module. This makes it both more flexibile to use and easier to add new features to as new needs crop up. Expect another blog post once the module is ready for use, and you can see all the improvements for yourself.

We're looking forward to building HelloSign integrations in Drupal 8 sites ... stay tuned.  

Free offer, talk to a seasoned Drupal expert.

Jul 06 2016
Jul 06

Development started on Drupal 8 features back in March of 2011. Since then, the developer and application framework world has looked forward to the outcomes of every development, feature completion, clean-up, API completion, beta, and release candidate (RC) phase with baited breath. In November of 2015, Drupal 8.0.0 was released. Sighs of relief turned to curious murmers—what’s this all about?

Drupal 8 takes an already terrific content management framework to ever greater heights for users, administrators, and developers. There’s a seriously sharp focus on user-friendliness, but content presentation, new ways to create data structures, build APIs, multilingual capabilities, and the delivery of mobile accessibility out of the box? Drupal 8 brings those to the table too.

Looking for help with Drupal 8?

There are 16 Drupal 8 features worth knowing.

While Symfony 2 powers the Drupal 8 backend, a lighter and faster core offers tons more capabilities for modules and themes. Plus, the Drupal 8 migration and the onward curve is significantly reduced. These changes and more are key reasons to consider that switch to Drupal 8. But I’m getting ahead of myself, here are the 16 top Drupal 8 features:

1. New Theme Engine

Drupal 8 includes a brand new theming engine called Twig, which is PHP-based, flexible, fast, and secure. It’s much easier to create beautiful and more functional Drupal websites using Twig, as its templates are written in a syntax that’s less complex than a PHP template or others while being more secure.

2. Mobile First From The Get-Go

Drupal 8 is mobile first in its approach. All the built-in themes that come with Drupal 8 are responsive, along with an admin theme that adapts to different screen sizes, and a ‘Back To Site’ button to go back to the front page. Tables fit into any screen size without a hitch, and the new admin toolbar works well on mobile devices.

3. More HTML5 Power to You

HTML5 is now more or less the de facto standard when it comes to writing web markup. The same is now available natively in Drupal 8, giving you access to input fields like date, e-mail, phone, etc., and even more functionality and compatibility with mobile and handheld devices.

4. Multilingual Ready

Drupal 8 boasts extensive multilingual features right out of the box. The admin interface has built-in translations. You can also create pages with language-based Views filtering and block visibility. Translation updates from the community are automatically facilitated.

5. Manage Your Configuration

Drupal 8 has configuration management built into it at the file-system level so that carrying over configuration elements (like content type, views, or fields, etc.) from local development to the server is a breeze. You can use a version-control system to keep track of configuration changes. Configuration data is stored in files, separate from the site database(s).

6. Easy Authoring

New Drupal 8 features bring unprecedented power into the hands of the Content Editor, with WYSIWYG editor CKEditor now bundled with the core. However, the most touted improvement remains the in-place editing capability that Drupal 8 will afford users, a result of the Spark Initiative.

Site and content creators or editors can edit text on any page without having to switch to the full edit form. Drafts are now much easier to create, and web security is now better implemented as a result.

7. Quick Edits

There’s something great about seeing something that needs changing and having the ease of access to change it—directly and quickly. Now Quick Edit is a backport of the Drupal 8 in-place editing for Fields. So if you’re logged into Drupal content is in front of you, edit the text directly for quick fixes and additions from the front-end.

8. Views Now Part of Core

Views sit high up in the Drupal module hierarchy, as it is an integral part of most website projects, and a lot is pretty much impossible without it. Site designers have used use this hitherto-contributed module to output galleries, maps, graphs, lists, posts, tables, menus, blocks, reports, and what-have-you.

With this Drupal 8 feature, Views is part of and firmly integrated with the core. The front page and several administration pages are now Views, and users will now be able to quickly create pages, blocks, admin sections, etc., and modify existing ones just as effortlessly.

9. Better Support for Accessibility

Drupal 8 has excellent support for industry standard accessibility technologies, like WAI-ARIA. ARIA Live Announcements API and TabManager are significant improvements in Drupal 8, which provide control for rich Internet applications. Bells and whistles like better font sizes, tweaked color contrasts, jQuery UI’s autocomplete, and modal dialogs go a long way towards making Drupal 8 a breeze to use.

Download our Ebook: Learn to select your best Drupal Partner

10. Web Services Built-in

Drupal 8 now makes it possible to use itself as a data source, and output content as JSON or XML. You can even post data back to Drupal 8 from the front end. Hypertext Application Language (HAL) is implemented in Drupal 8 and makes exploitation of web service capabilities less painful.

11. Fields Galore

Drupal 8 ships with bucket-loads of field types in the core, thus taking its content structure capabilities up a notch. New field types like entity reference, link, date, e-mail, telephone, etc., aid content creation, and now you can attach fields to more content types, as well as create custom contact forms by attaching fields to them.

12. Guided Tour

Now the descriptive text is right under the help link. Users can click and then take the tour; pop-ups appear, explaining how this all works, one of the most helpful Drupal 8 features to newcomers. This user-friendly boost is well-received as it’s making the CMS easier for everyone to understand.

13. Loading Speed

Drupal 8 caches all entities and only loads JavaScript when necessary. When a page is viewed, its content doesn’t need to be reloaded again. Previously viewed content is quickly loaded from the cache. Once configured and enabled, caching is completely automatic.

14. Industry Standards

Drupal 8 aligns with the latest PHP 7 standards like PSR-4, namespaces, and traits, and uses top notch, outstanding external libraries like Composer, PHPUnit, Guzzle, Zend Feed Component, Assetic to name a few. Meanwhile, underlying Drupal 8 features modern, object-oriented code that’s the order of the day, by Symfony 2.

15. JavaScript Automated Testing

Automated testing is not possible for front-end, so JaveScript (JS) automated testing is now possible with Drupal 8.1. Now QA’ers can test the JavaScript front-end automatically, saving time and making continuous integration that much easier.

16. Big Pipe in Core

With Big Pipe part of Drupal core, developers can optimize the site load performance for the end-user significantly. While this feature has nothing to with actual performance and is only perceived, it’s a great feature to have since the end user is able to see a difference in site load times.

Enough Drupal 8 features to think about?

These 16 Drupal 8 features are some of the most important reasons that this upgrade is so worth celebrating; it’s the collective work of over 3,000 contributors. But more importantly to you, this might be that big, bright answer you’ve been searching for.

Got Drupal 8 your mind?

More Drupal 8 resources:

This article was originally published in July, 2014. It has since been updated.

Apr 15 2015
Apr 15

Features_D8

The first Alpha version of the Features module for Drupal 8 is now available! “But wait!” you say. “I thought we didn’t need Features anymore now that we have the Configuration Management Initiative (CMI) in Drupal 8?”

This article will explain why some sites will still need Features, how Features works with CMI, and how Drupal 8 Features differs from the Drupal 7 version.

Features and CMI

Built in Drupal 8 core, CMI cleanly and consistently separates “content” (articles, blogs, etc) from “configuration” (views, content types, fields, etc). Rather than forcing each module to create its own import and export format, CMI uses YAML (yml) files to store configuration data. CMI also provides mechanisms for deploying configuration between sites, including development, test, and production environments.

Drupal 7 didn’t have CMI, and because the Features module could export and import configuration data as code modules, Features was often used for configuration management and deployment. But Features wasn’t designed to be a full configuration management system. Features was initially written to “bundle reusable functionality”.  The classic example was creating a Photo Gallery which was a bundle of a content type, some fields, a view, and an image style.

Features_D8_Edit-300x205

To create a Photo Gallery module in Drupal 8, you need to use the “single export” option in CMI to export your content type, then export your fields (and field storage), then export your view, then export your image style, and then hope that you haven’t missed any other important settings. This very manual process is subject to errors. Luckily, the Features module in Drupal 8 allows you to pick and choose what configuration data you want to add to your custom module, simplifying the process.

Features in Drupal 8 uses CMI as a consistent storage mechanism, in addition to importing and exporting configuration. Both the user interface and drush command line support are similar to the Drupal 7 version many developers are accustomed to.

New Features in Features

Rather that rewriting Features from scratch for D8, we started with the excellent “config_packager” module from nedjo. His module was created to export “packages” of configuration in D8, which is really the intended use-case of Features. During the past few months I have worked closely with nedjo to merge his config_packager concepts into the new Features module, which gives users some very cool new functionality. It’s been a great example of how open source collaboration often produces better results than either individual effort.

Assignment Plugins

One awesome idea from config_packager was plugins that can automatically assign existing site configuration into packages. When you first install Features and go to the listing page within the Configuration Management section of your site, you will see that it auto-detects your content types (article, page) and creates Features for exporting Features_D8_Pluginsthese content types, automatically including any fields, views, or other configuration assigned to that content type.

You can control which assignment plugins are enabled, and what order they run. Each plugin can have it’s own configuration. For example, the “Base” assignment plugin lets you choose which component should be the “base” for organizing configuration. By default, the base is “content type.” If you change the base to “views” then your site configuration will be organized into Features based upon each view on your site.

These assignment plugins solve the problem of organizing and modularizing your configuration. They also better modularize functionality within Features, such as auto-detecting dependencies, adding profile configuration, or excluding configuration that has already been exported to a module.

Bundles

Assignment plugins are a great concept, but we wanted to support multiple plugin settings to enable easy switching between “show config organized by content type” and “show config organized by views.” In addition, we wanted to add “namespaces” to Features to better isolate configuration exported to different profiles. For example, “namespaces” make it easier to support sites running multiple distributions, such as Open Atrium running on Panopoly, where some Features are prefixed by oa_* and other Features are prefixed by panopoly_*.

In D8 Features we implemented “bundles” to specify the namespace (prefix) of Features modules, similar to the “package” tabs along the left side of the Features listing in D7. These bundles can be assigned to a specific profile, such as Panopoly or Open Atrium and will filter the Features listing to only show modules within the bundle’s namespace. Assignment plugin settings are stored within the bundle, allowing different bundles to organize configuration in different ways. You can also easily export configuration to a different bundle, making it finally easy to copy your Features from one namespace to another.

Features is for Developers

Drupal 7 didn’t have CMI — core support for configuration management was added via Features. If a custom module contained configuration exported by Features, you needed to have the Features module enabled (in most cases), even on Production, to use that module. In Drupal 8 we wanted to remove the dependency on the Features module. When you create a module using Features D8, the module will work on any other D8 site even without Features being installed!

In Drupal 8, configuration is owned by the site and not by modules. This is a very important design decision behind CMI and how your site configuration is managed and deployed. Configuration provided by a module is imported into the site only when the module is enabled. Once the configuration is imported, any changes made to the config files in the module are ignored by the site. The only way to re-import the configuration is to uninstall the module and then reinstall it.

Drupal 8 also does not allow you to enable a module that contains configuration that already exists on the site. This can cause problems with updating configuration provided by a module. For example, if the Photo Gallery view within our Gallery module needs to be changed, you normally need to uninstall the module and then reinstall it. However, some configuration is not removed when you uninstall a module. Thus, you can have a situation where you uninstall the module and then cannot reinstall it because the configuration already exists. You must manually delete the view provided by the module before you can re-enable the module.

These hurdles and restrictions can make developing modules that contain configuration difficult. As a developer, Features provides functionality to help with these issues. When the Features module is active, it allows you to enable a module that contains configuration already on your site. Once a module is enabled, Features allows you to Import changes from that module into your site without needing to first uninstall the module. This prevents the situation of having a module that cannot be re-enabled, or a module that cannot be uninstalled because of dependencies and makes it much easier to update the configuration stored in the module during development.

You only need to install the Features module in your development environment. Once you have updated your feature module and imported the configuration changes into your dev environment, you then use normal Drupal 8 CMI to deploy configuration to staging and production. If you still want to keep the Features module enabled on staging or production for doing config imports, you can disable the Features UI submodule and only use the drush interface.

Overriding Configuration

If you change configuration in Drupal 8 that was imported from a module, Features will detect and display this change. If you import the new module configuration, it will overwrite the active site configuration. If you export the changes you will update the config data stored in your module. CMI controls the granularity of this configuration. For example, an entire View is a single configuration entity. Thus, there is no way to only import a simple change, such as the title of the view. Importing the view will overwrite the entire view, replacing any other changes that might have been made.

So far there isn’t any way to manage partial configuration changes in Drupal 8. CMI was specifically designed not to handle partial configuration. Currently a module that needs to update partial configuration needs to implement an update hook. However, the code to update a partial configuration object is very specific to the configuration being changed. There is no overall consistent way to “merge” configuration between the module and active site. The config_synchronizer module is the beginning of some good ideas on monitoring site config changes to determine if it is safe to import new config from a module and might be the start of a better Features Override module in the future.

drupal8My Thoughts on Drupal 8

Rewriting Features for D8 was a very interesting project for me. I started with little knowledge of the guts of Drupal 8. I’m actually amazed by the amount of work that has gone into Drupal 8 to make it look and feel like Drupal (Views, Content Types, etc) and yet have a completely different architecture based on Symfony.

Working on Features for Drupal 8 was actually a joy.

Once I got the hang of some of the new concepts such as services and routing and plugins, it was actually fun to create Features. Sure, there are still some rough edges and some core config formats changed even during the Drupal Beta that caused some things in Features to break.

Ultimately I challenge developers to give Drupal 8 a chance and start “poking the tires” to give it a spin. In only four weeks I was able to learn D8 and produce a useable module for something as complex as Features (while also learning config_packager and doing a lot of refactoring). It’s not nearly as onerous to develop in D8 as I had been led to believe by some bloggers. I’m very excited for this new chapter of the Drupal story and also happy that Features will be playing a much smaller part in that story than ever before.

Conclusion

If you want to learn more about Features and see a demo, come to my session at DrupalCon LA next month: Features for Drupal 8. If you want to help, go to the Features project page on drupal.org and download the latest 3.x version and start playing with it.  Post your bugs and suggestions to the issue queue. We could really use some help writing automated tests in order to release a Beta version. I am looking forward to our bright future in Drupal 8 where we no longer need to curse about Features and can focus back on building reusable functionality.

Apr 15 2015
Apr 15

Features_D8

The first Alpha version of the Features module for Drupal 8 is now available! “But wait!” you say. “I thought we didn’t need Features anymore now that we have the Configuration Management Initiative (CMI) in Drupal 8?”

This article will explain why some sites will still need Features, how Features works with CMI, and how Drupal 8 Features differs from the Drupal 7 version.

Features and CMI

Built in Drupal 8 core, CMI cleanly and consistently separates “content” (articles, blogs, etc) from “configuration” (views, content types, fields, etc). Rather than forcing each module to create its own import and export format, CMI uses YAML (yml) files to store configuration data. CMI also provides mechanisms for deploying configuration between sites, including development, test, and production environments.

Drupal 7 didn’t have CMI, and because the Features module could export and import configuration data as code modules, Features was often used for configuration management and deployment. But Features wasn’t designed to be a full configuration management system. Features was initially written to “bundle reusable functionality”.  The classic example was creating a Photo Gallery which was a bundle of a content type, some fields, a view, and an image style.

Features_D8_Edit-300x205

To create a Photo Gallery module in Drupal 8, you need to use the “single export” option in CMI to export your content type, then export your fields (and field storage), then export your view, then export your image style, and then hope that you haven’t missed any other important settings. This very manual process is subject to errors. Luckily, the Features module in Drupal 8 allows you to pick and choose what configuration data you want to add to your custom module, simplifying the process.

Features in Drupal 8 uses CMI as a consistent storage mechanism, in addition to importing and exporting configuration. Both the user interface and drush command line support are similar to the Drupal 7 version many developers are accustomed to.

New Features in Features

Rather that rewriting Features from scratch for D8, we started with the excellent “config_packager” module from nedjo. His module was created to export “packages” of configuration in D8, which is really the intended use-case of Features. During the past few months I have worked closely with nedjo to merge his config_packager concepts into the new Features module, which gives users some very cool new functionality. It’s been a great example of how open source collaboration often produces better results than either individual effort.

Assignment Plugins

One awesome idea from config_packager was plugins that can automatically assign existing site configuration into packages. When you first install Features and go to the listing page within the Configuration Management section of your site, you will see that it auto-detects your content types (article, page) and creates Features for exporting Features_D8_Pluginsthese content types, automatically including any fields, views, or other configuration assigned to that content type.

You can control which assignment plugins are enabled, and what order they run. Each plugin can have it’s own configuration. For example, the “Base” assignment plugin lets you choose which component should be the “base” for organizing configuration. By default, the base is “content type.” If you change the base to “views” then your site configuration will be organized into Features based upon each view on your site.

These assignment plugins solve the problem of organizing and modularizing your configuration. They also better modularize functionality within Features, such as auto-detecting dependencies, adding profile configuration, or excluding configuration that has already been exported to a module.

Bundles

Assignment plugins are a great concept, but we wanted to support multiple plugin settings to enable easy switching between “show config organized by content type” and “show config organized by views.” In addition, we wanted to add “namespaces” to Features to better isolate configuration exported to different profiles. For example, “namespaces” make it easier to support sites running multiple distributions, such as Open Atrium running on Panopoly, where some Features are prefixed by oa_* and other Features are prefixed by panopoly_*.

In D8 Features we implemented “bundles” to specify the namespace (prefix) of Features modules, similar to the “package” tabs along the left side of the Features listing in D7. These bundles can be assigned to a specific profile, such as Panopoly or Open Atrium and will filter the Features listing to only show modules within the bundle’s namespace. Assignment plugin settings are stored within the bundle, allowing different bundles to organize configuration in different ways. You can also easily export configuration to a different bundle, making it finally easy to copy your Features from one namespace to another.

Features is for Developers

Drupal 7 didn’t have CMI — core support for configuration management was added via Features. If a custom module contained configuration exported by Features, you needed to have the Features module enabled (in most cases), even on Production, to use that module. In Drupal 8 we wanted to remove the dependency on the Features module. When you create a module using Features D8, the module will work on any other D8 site even without Features being installed!

In Drupal 8, configuration is owned by the site and not by modules. This is a very important design decision behind CMI and how your site configuration is managed and deployed. Configuration provided by a module is imported into the site only when the module is enabled. Once the configuration is imported, any changes made to the config files in the module are ignored by the site. The only way to re-import the configuration is to uninstall the module and then reinstall it.

Drupal 8 also does not allow you to enable a module that contains configuration that already exists on the site. This can cause problems with updating configuration provided by a module. For example, if the Photo Gallery view within our Gallery module needs to be changed, you normally need to uninstall the module and then reinstall it. However, some configuration is not removed when you uninstall a module. Thus, you can have a situation where you uninstall the module and then cannot reinstall it because the configuration already exists. You must manually delete the view provided by the module before you can re-enable the module.

These hurdles and restrictions can make developing modules that contain configuration difficult. As a developer, Features provides functionality to help with these issues. When the Features module is active, it allows you to enable a module that contains configuration already on your site. Once a module is enabled, Features allows you to Import changes from that module into your site without needing to first uninstall the module. This prevents the situation of having a module that cannot be re-enabled, or a module that cannot be uninstalled because of dependencies and makes it much easier to update the configuration stored in the module during development.

You only need to install the Features module in your development environment. Once you have updated your feature module and imported the configuration changes into your dev environment, you then use normal Drupal 8 CMI to deploy configuration to staging and production. If you still want to keep the Features module enabled on staging or production for doing config imports, you can disable the Features UI submodule and only use the drush interface.

Overriding Configuration

If you change configuration in Drupal 8 that was imported from a module, Features will detect and display this change. If you import the new module configuration, it will overwrite the active site configuration. If you export the changes you will update the config data stored in your module. CMI controls the granularity of this configuration. For example, an entire View is a single configuration entity. Thus, there is no way to only import a simple change, such as the title of the view. Importing the view will overwrite the entire view, replacing any other changes that might have been made.

So far there isn’t any way to manage partial configuration changes in Drupal 8. CMI was specifically designed not to handle partial configuration. Currently a module that needs to update partial configuration needs to implement an update hook. However, the code to update a partial configuration object is very specific to the configuration being changed. There is no overall consistent way to “merge” configuration between the module and active site. The config_synchronizer module is the beginning of some good ideas on monitoring site config changes to determine if it is safe to import new config from a module and might be the start of a better Features Override module in the future.

drupal8My Thoughts on Drupal 8

Rewriting Features for D8 was a very interesting project for me. I started with little knowledge of the guts of Drupal 8. I’m actually amazed by the amount of work that has gone into Drupal 8 to make it look and feel like Drupal (Views, Content Types, etc) and yet have a completely different architecture based on Symfony.

Working on Features for Drupal 8 was actually a joy.

Once I got the hang of some of the new concepts such as services and routing and plugins, it was actually fun to create Features. Sure, there are still some rough edges and some core config formats changed even during the Drupal Beta that caused some things in Features to break.

Ultimately I challenge developers to give Drupal 8 a chance and start “poking the tires” to give it a spin. In only four weeks I was able to learn D8 and produce a useable module for something as complex as Features (while also learning config_packager and doing a lot of refactoring). It’s not nearly as onerous to develop in D8 as I had been led to believe by some bloggers. I’m very excited for this new chapter of the Drupal story and also happy that Features will be playing a much smaller part in that story than ever before.

Conclusion

If you want to learn more about Features and see a demo, come to my session at DrupalCon LA next month: Features for Drupal 8. If you want to help, go to the Features project page on drupal.org and download the latest 3.x version and start playing with it.  Post your bugs and suggestions to the issue queue. We could really use some help writing automated tests in order to release a Beta version. I am looking forward to our bright future in Drupal 8 where we no longer need to curse about Features and can focus back on building reusable functionality.

Mar 02 2015
Mar 02

The Features module helps address the shortcoming in Drupal 7 of how to manage and deploy site configuration data.  There are times when you need to change a Feature.  The Features Override module can help with this, but sometimes doesn’t solve the problem completely.  In this article I will discuss all the different ways to override your Features and the common problems associated with that.  While this has been an issue for years, it’s become more common recently with the advent of Distributions such as Open Atrium and Panopoly which heavily use Features and which expect the users to upgrade to new versions.  Maintaining your site customizations when upgrading a distribution using Features Override has become a more common need.

The Problem

How do I override configuration from an existing Feature  within my site-specific project?

Solutions

Cloning the base module (not recommended)

If you need to make extensive changes you might need to clone the base module and then customize it.  Disable the original module, uninstall it, then enable your site-specific module.

Pros Cons
  1. You have full control over all aspects of the original module.
  2. Keeps the overrides nicely separate in their own modules that can be enabled/disabled/deployed.
  3. The original Features will never be shown “overridden” (because the original is uninstalled!)
  1. Any future bug fixes, improvements, updates to the original module will not be available.
  2. Since future security patches to the original module won’t be available, this might add a security risk to the project or force maintainers to monitor the original module for updates and apply them to the cloned version.

Using settings.php

If you just need to change a variable (from variable_get) you can do this via the $conf[] array in your site settings.php file.  This method is typically used for environment-specific settings, such as databases, search servers, caching settings, etc.  You can also set the $conf[] array within a custom module if you need to deploy the change across all your environment.  Avoid using variable_set() to change the variable since that will update the database directly as mentioned below.

Pros Cons
  1. The original feature containing the variable (via Strongarm) won’t be marked as “overridden”
  1. Only works for Variables (Strongarm Features)
  2. settings.php not typically part of the code repo, so need to ensure it is version controlled some other way.
  3. Sometimes developers forget to check settings.php for variable overrides, making ongoing support tricky.
  4. Best for Environment variables rather than for any generic Drupal variable.

Update the Database directly

You can create an update hook, or other Drupal hook (hook_enable, hook_install) and update the database directly via SQL or other API functions.  For variables you can use variable_set() to save the new value to the database.  This is only recommended as the last resort for configuration not supported by Features Override.

If you must update the database directly, be sure to only do it once and not in a hook such as hook_init that runs with each page load.  Updating the database on each page load can kill the performance of your site.  With variable_set() you can do this by first calling variable_get() and only saving the value if it needs to be changed.

Pros Cons
  1. Sometimes it’s the only way.
  2. Can keep the overrides separate in their own modules
  3. Only applies specific changes and allows future updates to the base Feature to be used.
  1. Reverting the base feature will change the database back to it’s original value, forcing you to re-run whatever SQL is needed to override it. Can be alleviated by Locking the original base Feature to prevent any reverts.
  2. If the original feature is locked, future bug fixes or improvements might not be available.
  3. The original feature will always be marked as “overridden”.
  4. Some configuration is not stored in the DB, such as Views (or other ctools-based components like Panels) that exist purely in code.

Implement an “alter hook” in code

Most configuration has some sort of “alter” hook that allows it to be modified after it is loaded from the database.  For example, Views calls hook_views_default_views_alter(&$data) to allow you to change any part of a view, whether that view comes from the DB or is in code.  You can create a custom module that implements the desired alter hooks and override the data directly.

Pros Cons
  1. Base Feature will not be marked as “overridden”.
  2. Keeps the overrides nicely separate in their own modules that can be enabled/disabled/deployed.
  3. Only applies specific changes and allows future updates to the base Feature to be used.
  1. Not all configuration has the needed hooks.
  2. Each component has a different hook name and different data structure to modify.

Use Features Overrides module

Similar to the above “Implement alter hook” the Features Override module is designed to create the alter hook implementations for you and export those as new Features modules that you can enable, disable, deploy.

Pros Cons
  1. Base Feature will not be marked as “overridden”.
  2. Keeps the overrides nicely separate in their own modules.
  3. Only applies specific changes and allows future updates to the base Feature to be used.
  4. Features Overrides does the work of figuring out which alter hooks can be used and how to override the data.
  5. Provides a UI for inspecting overrides.
  6. Allows an entire component to be altered (e.g. entire view), or just a single change (e.g. just the title of a view)
  7. Works properly with Features. An Override is just another Feature module on the site.
  1. Not all configuration has the needed hooks.
  2. Can be tricky to “override an override”.

Typical Problems

Feature is stuck at being “overridden”

The most common difficulty is a base Feature marked as “overridden” that does not go away when the feature is reverted.  ”Overridden” simply means that the value of the configuration stored in the DB is different from what is stored in the exported Feature code file.  Features literally re-generates the feature export internally from the DB and compares the code with what is stored on disk.  Doing a “drush fd featurename” simply shows the code diff between the code stored on disk (shown in red) with the code generated from the current database (shown in green).

To determine if a Feature is overridden, Features actually takes the generated code, sanitizes it, sorts it, executes it, and then does an md5 checksum on it.  If the two checksum values are different, the Feature is marked as “overridden”.  However, the “drush fd featurename” command shows the actual code difference regardless of if it’s marked as “overridden”.

This behavior means that “drush fd” might output code differences that actually don’t cause the feature to be overridden.  For example, if you change the order of dependencies in your module.info file and then run “drush fd” on the feature, you’ll see it display those changes, even though a “drush fl” won’t show the feature as overridden.

This makes it difficult sometimes to debug why a feature is overridden, since not all of the output of “drush fd” is relevant.  You need to look for actual value changes, rather than just re-ordering changes.

Adding a new module

Sometimes, just enabling a new contrib module will cause your Features (especially field features) to be “overridden”.  If the new module adds some new settings, formatters, widgets, etc then these settings will be active in the DB but not reflected in the code.  So the Feature will be shown overridden.  Reverting the feature won’t have any affect because there is no way to remove the new settings from the DB without uninstalling the new module.

These kinds of overrides are annoying, but not actually that important.  They don’t prevent the feature from being reverted when a new version of the base module is released.  They are not caused by any site-specific change that would be lost by a revert.  Typically it’s best to just document these cases and leave them as overridden.  Just be careful to not become complacent and make a site customization in the future to the same feature and then ignore that it’s overridden and lose your changes when you revert.  You should periodically do a “drush fd” on overridden features just to be sure what is shown is still just from the new module you installed.

A disabled module

Similar to the above, but the opposite case.  If you have disabled a module that was used when the original Feature was exported, then the code might have settings for that module that are no longer in your database.  Once again you won’t be able to remove this by reverting.  Again, you can just document these cases.  But make sure you really need to have the module disabled.  Having a module enabled that you are not using is not a big performance impact.  The time saved in long-term maintenance of the site it typically more important than worrying about an extra module.

A bad override

If you have used some of the not-recommended approaches for overriding a base Feature, such as writing directly to the DB, then you will end up with an overridden feature that cannot be reverted.  Or if the Feature is reverted, you might lose the change that was written to the DB and need to reapply it.  Even if the Feature is locked to prevent reverting, it will still be listed as overridden.

Another type of “bad override” is using the wrong kind of alter-hook to try to modify configuration.  If the alter hook is called in a way that makes it look like a DB change to Features, then Features is going to see a difference between the DB and code and mark it as overridden.

Overridden Views and Panels

Some modules, such as Views and Panels have their own “override” functionality.  These “pure” Features can exist purely in code with nothing in the DB.  When you make a UI change to a View, it gets copied from the code into the DB and your change is made to the DB.  The View is then marked as “overrides code” in the Views listing.  A View that came from code can be “reverted” within the Views UI.  This essentially just deletes the version of the view in the DB so that the code takes affect again.

Sometimes you can get a View stored in the DB that still matches the code.  For example, you change a View in the UI (causing it to be copied to the DB), then you edit the View and undo the change.  Now it matches the code again, but the view is still in the DB.  In this case, the View Feature will not be shown as “overridden”, but in the Views listing it will still say “overrides code”.

When changing a pure Feature like a View via code (like in an alter hook), your changes will take affect immediately, or possible after a cache clear.  No revert will be necessary because there is nothing in the DB to update.  However, in the above case where you have changed a view and then changed it back so it’s stored in the DB, changing the code will not affect the View until you revert the Feature to remove the DB copy of the old view.

In general, if you are having issues with Views, Panels, or other ctools-like pure Features, make sure they are not overridden in their respective UIs.  For example, click the Revert option for the View within the Views listing to ensure it’s actually using the View stored in code.

Wrong version of Features

If the code in the Feature was exported using a different version of Features than what is on your site, there might be changes that cause overrides.  Ensure your version of Features matches the version used to generate the export.  This usually only applies to major version numbers and is not normally a problem.  Normally updates to the Features module are made in backwards-compatible ways to prevent this.  But certainly be sure your version of Features on your site is not older than the version that generated the base code.  Always try the latest version of Features to see if it helps.

Nobody should be using the 1.x branch of Features anymore.  There is no reason for this.  All Drupal 7 sites should be on the 2.x branch.

Unsupported Component

As mentioned, not all configuration components support Features Override, or only support it partially.  For example, Panelizer works with Features, but doesn’t work well with Features Override because it still depends on the specific order of items in it’s config array and when the alter-hook generated by Features Override tries to change something, that array order might not be preserved.  Sometimes in this case you can create your own alter-hook implementation that overrides the code properly.

This might also be an opportunity to help improve Features Override or suggest patches to the module in charge of the configuration to better support Features Override.

Living with Overrides

What if you have tried all of this advice and your Feature is still marked as overridden?  And what if this override represents a specific site change that you need to maintain and ensure never gets reverted?  The solution to this is to “lock” your feature component.  Go to the Structure/Features page and select the Feature that is marked as overridden.  Click the small “lock” icon next to the overridden component in the right column.  The component will still be listed as “overridden” but when you revert your Features the locked component will be skipped, ensuring that your customization remains in place.

When locking your Features, try to only lock the specific component rather than locking the entire Feature.  The downside to locking a component is that any changes to that component from a new version of your distribution won’t take affect.  This is similar to the consequences of the “Update the Database directly” option listed above.  However, sometimes this is the only alternative.

Conclusion

Just keep in mind that both Features and Features Override are just implementing hooks (normal hooks for Features, alter-hooks for Features Override) that are exposed by Drupal or contrib module.  If those hooks don’t exist or don’t work properly there isn’t much Features or Features Override can do about it.  Drupal 7 doesn’t have any sort of configuration management in core, so every contrib module does it differently.  ctools-based modules have more of a standard framework, as does entity API.  Features itself tries to add code to handle core components such as Fields, Content Types, etc that don’t have the needed hooks.  But there is often a limit to how much Features can do and just patching stuff into the DB is not usually a good solution.

Don’t “hate” Features or Features Override.  Life was much worse without them.  They are the best solution to solving configuration management problems in Drupal 7.  They have been developed over years of experience.  Try to help improve them before trying to implement your own configuration or override architecture.

Drupal 8

Don’t count on Drupal 8 magically solving all of these issues.  The Configuration Management Initiative (CMI) within Drupal 8 was focused on handling site configuration, but not on “bundling functionality”.  It provides an API, storage mechanism, and framework for deploying configuration.  CMI helps a lot, but there are still issues around around component granularity and overriding configuration.  In Drupal 8, configuration is owned by the site rather than owned by a module.   This will make bundling functionality (ala Features original intent) more difficult.  We will be working on Features for D8 soon, but this is still mostly unknown territory.  For now, take a look at some existing modules such as config_packager and config_devel.

I’ve submitted a session to DrupalCon Los Angeles on Features in Drupal 8.  Add a comment and support!

Sep 29 2014
Sep 29

Some time ago, a client asked me about the features module. He wanted to know what the features module is about and how it can help him with his project. Their set up was a pretty complex e-commerce application involving multiple content types and integration with 3rd party services. Yet, they were not using features and would manually replicate any changes from the developer's machine to the server. He was concerned about maintaining the site and how he could add some new functionality without breaking the existing configuration. My recommendation was that they start using features. He had not idea what it was so I wrote him an email explaining. This gave the idea of this blog post.

What is the features module?

The purpose of the Features module is to copy configuration setups from one drupal site to another. It creates "packages" of the settings that can be shared among different sites. Today it is used in almost every development workflow to deploy changes from one environment to the other. Drupal 8 comes with a more advanced functionality in core. It is called configuration management (https://drupalize.me/blog/201401/drupal-8-configuration-management-walk-...) . From the features project page in drupal:

Features provides a UI and API for taking different site building components from modules with exportables and bundling them together in a single feature module. A feature module is like any other Drupal module except that it declares its components (e.g. views, contexts, CCK fields, etc.) in its .info file so that it can be checked, updated, or reverted programmatically.

Why is feature so popular?

Drupal 7 stores every configuration setting in the database. This poses a problem when the developer wants to copy a content type or a view or some settings from one site to another. This is the problem that features try to solve. Features allow the developers to export those settings in files and then import them to another environment/site. You can think of features as special kind of modules. In drupal 8, thanks to the Configuration Management Initiative, every setting is stored in files. Keeping the configuration settings in files has many advantages:

    1. The configuration can be tracked in version control systems
    1. The configuration can be reused/shared
    1. The deployment workflow is greatly simplified.

This result in less bugs, less frustration, better quality and ultimately faster (=cheaper) results.

How do features work?

Assume that the developer creates a new content type and he wants to copy it to the development server. Here is what he will do with features: 1. He adds the content type to an existing feature (or creates a new one). features will automatically detect any dependencies (eg modules implementing the fields) 2. He downloads the features and copies it to the custom modules folder. Then he pushes it to the version control system. 3. The features module is pulled to the development site 4. The feature is enabled and the content type is automatically created. Now assume that he makes some changes to the content type. Here is how he copies to changes to the site: 1. Updates the feature using the features UI or using drush (this causes the feature to pick up the changes) 2. Pushes the feature to the live site 3. He reverts the feature in the live site so that the changes are activated.

Do I need it?

If you plan to deploy some new functionality for your web site then the chances are that you will need it. Having questions? use the comments section below or Contact me.

Aug 26 2014
Aug 26

Features is one of those modules we can not do without. One annoying issue with features is that it is slow. The bigger the drupal site, the slower the features UI pages load. And waiting for the page to load is one of the most disturbing things during drupal development.

Adding a new component to a feature is a multistep process: Go the features page, add the component to the feature, download the feature, remove the old feature and extract the new one. And repeat many times during the day.

Fortunately, we can speed this process quite a bit. Drush to the rescue again! This post will explain how to use drush to add new components to a feature.

Add a component to a feature with drush

We can use drush to add component to a feature using the features-export command.

Here is the command help information:

➜  drush help fe
Export a feature from your site into a module. If called with no arguments, display a list of available components. If called with a single argument, attempt to create
a feature including the given component with the same name. The option '--destination=foo' may be used to specify the path (from Drupal root) where the feature should
be created. The default destination is 'sites/all/modules'. The option '--version-set=foo' may be used to specify a version number for the feature or the option
'--version-increment' may also to increment the feature's version number.

Arguments:
feature                                   Feature name to export.                                                               
components                                Patterns of components to include, see features-components for the format of patterns.

Options:
--destination                             Destination path (from Drupal root) of the exported feature. Defaults to 'sites/all/modules'.
--version-increment                       Increment the feature's version number.                                                      
--version-set                             Specify a version number for the feature.                                                    

Aliases: fe

Assuming you have a view called content_list and a feature called f_registration_views, here is how you add the view to the feature.:
drush fe -y f_registration_views views_view:content_list --version-increment
If the feature above does not exist, it will be created.

That's great. But how do you add a content type, or a rule to a feature? We need to know what components are available and the sources for each component:.

LIst the components avaiable

There is another drush command that lists all the component in a drupal site. :

➜  drush fc node          
Available sources                                            
node:page              Provided by:f_registrations_content_types
node:article

The above says that there are 2 content types in the system: article and page. Additionally, the page content type is already contained in a the f_registrations_content_types feature. To add the article content type the the same feature use drush fe egain:

drush fe -y  f_registrations_content_typesnode:article --version-increment

Use drush fc to get a list of all the available components:

When working with features do not forget about the other commonly used features commands:

drush fra
drush fua
drush fl

Jul 16 2013
joe
Jul 16

It's been a really long time since I've worked on a Drupal build that didn't make use of the features module in some way or another. For better or worse it's turned into one of those modules like Views that's simply a part of the expected toolkit for many projects. Yet I still occasionally meet people who haven't heard of it yet. It's always fun to see the lightbulb over their head when you explain it to them and you can see the gears start churning as they immediately start imagining all the tedious box checking they can eliminate from their daily workflow.

The 2.x version of Features came out not too long ago and we are starting to make use of it in our work. It's a great update that's added a few new elements and greatly improved the usability of the the module. It reminds me again how important this module has become to solving so many different problems for us. So I want to take this opportunity to remind you that it exists. And for those of you who haven't used it before, hopefully this post will get the gears churning a little bit.

What exactly does Features do?

James Sansbury wrote an excellent retrospective on the Features module that does a good job of explaining the problem space and how we ended up with the Features module. In summary, one of the things that makes Drupal awesome is the ability to do so much site building without ever having to write any code. You can create content types, click together views, and change the default behavior of the user registration process all through your browser. The challenge in this is deploying those changes to other team members or from a development instance on your laptop to a live site.

Because content is likely continuing to be generated on the live site whilst you work away on your flashy new view you can't (???) simply replace the database on production with a copy from your laptop. We need a way to remember the configuration changes that we made on our local environment, so we can replicate them in the production environment. Enter Features. I often think of features as way of automating the things that I used to record in a checklist. Deploying meant going through my checklist and configuring those things on the live site really fast; hoping no one saw the site when things were broken for a few minutes. This presentation from DiWD 2008, while a little dated, does a good job of explaining the problem space.

Tell me more!

Want to learn more about using Features in your own workflow? Here are some good resources to help get you started:

In addition to the blog post linked above, James also has a recorded presentation that covers a lot of the high-level who, what, and why of features.

We have a complete series on creating features and deploying them with Drush that covers the majority of things you're likely to do with Features in your day-to-day workflow.

While Drush isn't required to use Features it certainly makes it more pleasant. If you haven't used Drush before or need some help we've got a series of videos covering Drush basics that will help you on that front.

I would also recommend taking a look at this blog post about naming things, since it's important to have a good naming convention when using Features.

Sometimes you're going to run into things within Drupal that can't be exported with the Features module. In this case, we still fall back on old reliable hook_update_N() and performing direct database queries. It's not always pretty, but it's a whole lot better than the checklist approach. If you find yourself needing to go this route, review this video on Altering the Database. It covers the process of creating your own update hooks, with a focus on altering the schema of an existing table. But you'll learn how to execute an update function and you can start adding your custom queries there.

Finally, what about writing your own modules and making the configuration data exportable via Features? We've got a short video about making things exportable via CTools. And in Drupal 7 you can make your custom entities built (using the Entity API)[] exportable with just a few extra tweaks to your controller.

Jun 04 2013
Jun 04

Features is a must have tool for deploying drupal sites. Features can be used for storing the website configuration in files, instead of the database. It can for example allow you to store a view in a file. You can then commit this code to your repo as usual.
Must of the site's configuration is stored in variables. Features, when used with strongarm, can be used to also export those variables from your staging env to your production. You can always find the name of the variable, by inspecting the html code. I use another trick to easily locate the variable name:

You can use

drush vget

to get the value of variable. For example,

drush vget cache

will return 1 or 0, depending on the value of the caching parameter set in admin/config/development/performance. If you dont know exactly the name of the variable, you can for example do a

drush vget pathauto

This will return all the variables that contain the word pathauto in the name.

Lets say that you need to change some variables of the pathauto module. Here is how to identify your variables:

drush vget pathauto > temp1

Change the module's options

drush vget pathauto > temp2

Then do a

diff temp1 temp2

The last command will show you which variables containing the word pathauto were altered by your operations. You can then use that name with strongarm on in a drush script to carry the variables to the desired env. Personally, I prefer using drush script, because it is faster and feels more direct.

To export a variable with drush, just type

drush vset var_name var_value

Did you like this post? Drop me a line in the comments below

Mar 19 2013
Mar 19

This week, I'll describe a particularly challenging component I had to deal with: inoffensive-sounding menu items. Should be easy, right? Well, it wasn't.

I won't get into the basics of creating multilingual menu items here. There is good documentation on how to get that set up using the i18n submodule i18n_menu. To provide a context for this post, I'll just mention that we are manually creating menu items, through the admin UI. We have two types of menu items:

  • Ones that should appear in both languages, localized, and pointing to the same place. Those are created with the language set to "Language neutral".
  • Ones that should only appear in a specific language. We set that language explicitly on the menu item's form.

Internally, the i18n_menu modifies the core menu_links and menu_custom tables by adding, among others, a language attribute to save the above info. In addition, the module creates a new text group called menu to save menu translations. In this group, each translation is identified by a menu name and mlid to refer back to the original menu item.

The first problem occurred even before we introduced Features into the mix. The decision to use the mlid as part of the translation identifier means that, across site stages and instances, menu items should have the same database primary key in order to be correctly translated. This design decision introduced a lot of instability in our configurations, for example preventing us from creating new menu items on the fly, for testing or customization purposes. In essence, we would have needed to stick to an install profile approach to manage the site configuration - which is a desirable goal in itself, but one we didn't pursue. In the mean time, our menu item string translations were only reliably showing on the machine where translation occurred, but not elsewhere. This clearly had to be fixed.

We found the module Entity menu links to solve one half of this problem. This module creates a uuid for each menu item, ensuring that uuid remains unchanged throughout the lifetime of the menu item. This module also modifies the core menu_links table by adding to it a uuid attribute.

Still, the string translations were being saved with the mlid. How to convince i18n_menu to use the uuid instead? That's where we had to write some code. The i18n architecture uses the concept of i18n objects that correspond to Drupal site components. We used the following code to override the i18n object info for menu items to use the uuid as a key:

/**
 * Implements hook_i18n_object_info_alter().
 */
function checkdesk_core_i18n_object_info_alter(&$info) {
  // Use UUID field to identify menu_link.
  $info['menu_link']['key'] = 'uuid';
  $info['menu_link']['load callback'] = 'checkdesk_core_i18n_menu_link_uuid_load';
}

/**
 * Callback to load menu_link by UUID.
 */
function checkdesk_core_i18n_menu_link_uuid_load($uuid) {
 if (!empty($uuid)) {
    $query = db_select('menu_links', 'ml');
    $query->leftJoin('menu_router', 'm', 'm.path = ml.router_path');
    $query->fields('ml');
    // Weight should be taken from {menu_links}, not {menu_router}.
    $query->addField('ml', 'weight', 'link_weight');
    $query->fields('m');
    $query->condition('ml.uuid', $uuid);
    if ($item = $query->execute()->fetchAssoc()) {
      $item['weight'] = $item['link_weight'];
      _menu_link_translate($item);
      return $item;
    }
  }
  return FALSE;
}

Unfortunately, the strings were still showing up with the mlid on the translation interface. After many a WTF incantation, we found that i18n_menu was not honouring the i18n object key attribute while creating the string identifiers. We submitted a patch to fix this.

At this point, we had successfully modified the indexing mechanism of i18n_menu to use uuids, as shown below. Our testing with manual .po files revealed that regardless of mlid differences, menu item translations were being successfully moved from one instance to another.

i18n_menu with UUID identifiers

Now menu item translations were made reliable across instances, but they still weren't being saved in a feature. The core Features module does support menu items, but it does not export the additional attributes we introduced above, namely language and uuid. We also need to export customized because i18n will not translate menu items that are not marked as customized.

We submitted a simple patch to Features that allows a hook_query_TAG_alter to extend the relevant query and return extra fields to be exported. Our implementation of this hook looks like this:

/**
 * Implements hook_query_TAG_alter() for `features_menu_link`.
 */
function checkdesk_core_query_features_menu_link_alter($query) {
  // Add missing attributes for translation.
  $query->fields('menu_links', array('uuid', 'language', 'customized'));
}

After this change, the exported menu links look like this (note the last 3 attributes on each entry):

/**
 * @file
 * checkdesk_core_feature.features.menu_links.inc
 */

/**
 * Implements hook_menu_default_menu_links().
 */
function checkdesk_core_feature_menu_default_menu_links() {
  $menu_links = array();

  // Exported menu link: main-menu:node/add/discussion
  $menu_links['main-menu:node/add/discussion'] = array(
    'menu_name' => 'main-menu',
    'link_path' => 'node/add/discussion',
    'router_path' => 'node/add/discussion',
    'link_title' => 'Create story',
    'options' => array(
      'attributes' => array(
        'title' => '',
      ),
      'alter' => TRUE,
    ),
    'module' => 'menu',
    'hidden' => '0',
    'external' => '0',
    'has_children' => '0',
    'expanded' => '0',
    'weight' => '-47',
    'uuid' => 'edc54df9-4aa8-bf84-dd89-ca0a351af23b',
    'language' => 'und',
    'customized' => '1',
  );
  // Exported menu link: main-menu:node/add/media
  $menu_links['main-menu:node/add/media'] = array(
    'menu_name' => 'main-menu',
    'link_path' => 'node/add/media',
    'router_path' => 'node/add/media',
    'link_title' => 'Submit report',
    'options' => array(
      'attributes' => array(
        'title' => '',
      ),
      'alter' => TRUE,
    ),
    'module' => 'menu',
    'hidden' => '0',
    'external' => '0',
    'has_children' => '0',
    'expanded' => '0',
    'weight' => '-49',
    'uuid' => '0bc3af5d-28a8-c864-bd93-f17d8bea2366',
    'language' => 'und',
    'customized' => '1',
  );
  ...
}

With these patches, we were able to reliably persist multilingual menu links using Features. The menu item translations are saved in the translations component of the feature, as described in part 1 of this series. They look like this:

/**
 * @file
 * checkdesk_core_feature.features.translations.inc
 */

/**
 * Implements hook_translations_defaults().
 */
function checkdesk_core_feature_translations_defaults() {
  $translations = array();
  $translations['ar:menu']['a6b48d33d248c146aa8193cb6f618651'] = array(
    'source' => 'Create story',
    'context' => 'item:edc54df9-4aa8-bf84-dd89-ca0a351af23b:title',
    'location' => 'menu:item:edc54df9-4aa8-bf84-dd89-ca0a351af23b:title',
    'translation' => 'أنشئ خبر',
    'plid' => '0',
    'plural' => '0',
  );
  $translations['ar:menu']['8578b45ff528c4333ef4034b3ca1fe07'] = array(
    'source' => 'Submit report',
    'context' => 'item:0bc3af5d-28a8-c864-bd93-f17d8bea2366:title',
    'location' => 'menu:item:0bc3af5d-28a8-c864-bd93-f17d8bea2366:title',
    'translation' => 'أضف تقرير',
    'plid' => '0',
    'plural' => '0',
  );
  ...
}

Now I need your help to review and support (and possibly enhance) the patches submitted to i18n and Features. Please visit them here:

As you know, the more people show interest in a patch, the more likely it will go in quickly. Your help is appreciated!

Next time, I'll describe other components of the multilingual puzzle: taxonomy terms, static pages, etc.

AttachmentSize 81.31 KB
Mar 05 2013
Mar 05

In my role as development team leader, I am responsible for the application architecture that allows other team members to focus on building functionality with minimum friction and rework. As such, one of my biggest tasks is to ensure that new features and configurations can be reliably deployed to the various stages: development, testing and production.

My current project is an Arabic/English application built on Drupal 7, that is deployed in multisite fashion to several partners. I use Features as a base configuration management system, and a number of extension modules to help me manage specific site components. The need to manage the configuration of multilingual components makes the task more complex, and in this series of posts I hope to describe a full recipe that's allowing our distributed team to commit code without overwriting existing settings.

Here are some of the main architectural components on the site:

  • Menus and menu links
  • Taxonomies
  • Static pages
  • Content types
  • Views
  • Rules
  • Heartbeat messages

All these components need to be shown in multiple languages, with the help of the Internationalization module and friends.

Although our application can be delivered in multiple languages, we do all our development on the English UI. When we switched the default language to Arabic, we found that all our menus, taxonomies, and field translations were no longer showing. And for good reason: Drupal does not store the source language of strings in its database, so i18n has to guess the source language - and by default, it considers the site's default language to be the source. Fortunately, you can explicitly specify the source language via the variable i18n_string_source_language. We decided to hard-code the value of this variable in settings.php like so:

// settings.php

// Hardcode i18n_string_source_language to prevent nasty surprises.
$conf['i18n_string_source_language'] = 'en';

// Load per-site configurations.
require 'settings.local.php';

The last line is just a directive that allows us to version-control settings.php for global configurations and loads settings.local.php for instance-specific settings such as database connection.

Because we're deploying across 3 stages, with several instances at each stage, we cannot afford to manually import .po files each time we create or modify a translation. In order to keep the UI translation workflow sane, we designated a specific stage as the recipient of all translation work, allowing the configuration manager (yours truly) to solve the problem of automating the deployment of these translations to other stages and instances. To this end, I wrote a Features plugin called Features Translations that persists the selected translations within a feature, as shown in the screenshot below:

Translations in the Features UI

A file called feature_name.features.translations.inc gets exported to the feature, looking like this:

/**
 * @file
 * checkdesk_core_feature.features.translations.inc
 */

/**
 * Implements hook_translations_defaults().
 */
function checkdesk_core_feature_translations_defaults() {
  $translations = array();
  $translations['ar:default'][] = array(
    'source' => 'The optional description of the taxonomy vocabulary.',
    'context' => '',
    'location' => '',
    'translation' => 'الوصف الاختياري لمعجم الوسوم.',
    'plid' => '0',
    'plural' => '0',
  );
  $translations['ar:default'][] = array(
    'source' => 'You are not authorized to access this page.',
    'context' => '',
    'location' => '',
    'translation' => 'غير مسموح لك بالوصول إلى هذه الصفحة.',
    'plid' => '0',
    'plural' => '0',
  );
  $translations['ar:default'][] = array(
    'source' => 'Function',
    'context' => '',
    'location' => '',
    'translation' => 'الوظيفة',
    'plid' => '0',
    'plural' => '0',
  );
  [...]
  return $translations;
}

In the next part, I'll discuss our handling of multilingual menu items, which took a considerable amount of effort and patches to Features and i18n!

AttachmentSize 69.53 KB
Nov 15 2012
Nov 15

Posted Nov 15, 2012 // 4 comments

Drupal can be a scalable platform that can handle high traffic and serve large volumes of data easily with the proper configuration set up and server layout.  The large number of themes and modules in the community makes site development extremely easy and valuable in a sense that you can develop a large set of features in a short period of time without too many hours burned on coding everything from scratch.

 

Knowing this, it’s tempting to simply install everything within your site.  However, if you are going to maintain a high-traffic website, it might be a good idea to offload some of these features elsewhere.

Plan and determine what features of your site should be maintained within your installation and which features should be hosted from external sources.  I’m not saying you should start copying and pasting embed codes from third party websites or start hosting all subsets of data and media files on separate servers.  More so, I recommend that you should entrust third party services to take care of certain features (especially if they can do it better than what exists in the module space) to minimize risk and increase performance.

There are plenty of modules that can help you with this.  For example, rather than use Drupal’s internal commenting module, you can rely on Facebook or Disqus to handle this for you.  Google Analytics is another way to analyze your site’s traffic externally.  I am also fond of other modules such as Paypal and Intuit Merchant Services, which handle credit card payments elegantly for you without the hassle of worrying about security right off the bat (assuming you configure your SSL certificates correctly).

Sharing (work) is caring!

So if, for example, all the comments on your site take up half the server space, wouldn’t it be nice to have someone take care of that so you don’t have to buy more server space?  You might be better off outsourcing that functionality elsewhere so that you can focus on more obscure features on your site.

I would suggest this approach for many reasons:

  • Reliable support for the application by a team of dedicated maintainers focused on one (or a few) functionalities

  • You can switch these features out with careful modularization

  • Simplifies your site’s architecture…and your job

  • More features outside Drupal’s framework

  • The features are readily available (in most cases)

  • More cost-effective (since the pricing is catered to sharing resources amongst multiple websites)

  • It’s kind of like running your website on several sites at the fraction of the cost (since these external services price their services efficiently to share them across various clients)

But do you trust other people with your information?

 You have to consider the potential repercussions that might occur if you do indeed take this route.  If you do decide to take this route, you should ask the following questions before you make the big move.

  • Is the service reliable?  If the service goes down, will my site go into utter chaos?

  • Is the data exportable?  If I build a new version of the site later on or if I want to use a different solution later, will it be easy to migrate it?

  • Does it have all the features I need and (a lot) more?  Can I trust that I won’t have to move to another solution 6 months from now?

  • Do I really want to own the data?  Will it be difficult to customize it however I want for my own needs?

  • Do I want to be liable for protecting the credit card numbers and other sensitive information in my database?

  • What does the terms of service say?  Do you truly own the data, or can they use it for certain purposes?

  • Do your users trust whoever is handling the data outside the site?  Will it tarnish your site’s reputation if you put it on the site?

You shouldn’t take some of these questions lightly.   Using a credit card processor with a history of data leakage or advertisement software that serves annoying and potentially malicious advertisements can ruin your site’s reputation.  It would be wise to do your research on anything you do externally before you implement it on your site.

Couldn’t I just create these features myself on my own separate servers?

If you have the funding and bandwidth to do it, go for it!   Many opt to use the Apache Solr module to delegate the search functionality away from the main site’s server to achieve this.  This approach is common and not unheard of.

Doing this requires more manpower.  Even if the features are developed externally, you still need to upgrade them internally.  Features maintained externally typically have the advantage of acquiring upgrades without a need to do anything on your end (that’s the beauty of webapps!).  Going this route, you should always subscribe to their blog to make sure you're aware of any changes they make on their end.

Note: At this point, you might think doing all this implies laziness.  Rest assured!  There is nothing wrong with good lazy, however, as long as you achieve the goal at hand.  When the job is done, the amount of work done on your end is trivial as long as you have the research and documentation to handle any future tasks proactively (i.e. be aware of any caveats and risks when using a service, and keep note of any muddy scenarios not covered by their guarantees).

In conclusion…

Remember a decade ago when things rarely ran on APIs, and most site maintainers typically have to copy and paste embeddable codes to achieve the same thing (not to mention the site’s architecture being bloated and messy after a while)?  In some cases, a lot of the code back then didn’t really fit everyone’s needs, so you tend to have a lot of duplicate codebases across sites that tend to go stale months after it gets implemented.

Consider it blessing that we’ve gone all this way to weave various web services into existing sites much easier while tapping into polished features without a sweat on your end!

As a Phase2 developer, Peter Cho strives to create elegant and efficient solutions to provide a positive user experience for clients.

Prior to joining Phase2, Peter worked for the Digital Forensics Center developing marketing and web ...

Nov 07 2012
Nov 07

Introduction

Building a feature using CRM Core profile is easy. In this demo we will demonstrate the step-by-step instruction on how to do it. Please note this is a follow up and more in-depth guide to http://www.trellon.com/content/blog/building-crm-core-feature.

What are we building

In this demo we will be building an “online petition” feature that allows a website to:

  1. Create an online petition for a particular cause.
  2. Collect information from petition signers such as name, email, city and state.
  3. Run a report to see how many people have signed the petition and optionally export the data to a spreadsheet.
  4. Display a counter to show how many people have signed a specific petition.

Why don’t we use Web-form

Webform is a popular and powerful data collection tool in Drupal. It can be used to achieve the items that are laid-out above, so why not use it?

  • Insufficient views integration
    To show the actual webform submission data, additional modules (webform views, data module, etc have to be installed and configured)
  • Type of information it can collect
    Webform does not use entity-field API therefore it is missing the ability to collect complex data types such as phone number, address, etc.
  • Lack of normalization
    Webform does not differentiate if information should belong to a contact, an activity, or others. If we create another petition and some signers from previous petition signed the new one we will have to do data correlation to determine that information and link the two petition signatures.

What you need

To get started, your will need to have CRM Core modules running on your Drupal installation and have the CRM Core Profile module enabled. The easiest way to get started is to grab a quick CRM Core Demo installation profile from github.

You should also be familiar with the Features module and exportable objects. Knowledge of using CRM Core and views is recommended as well.

Building the components

Creating a “Petition” content type

We will first start by creating a content type called “Online petition”, this content type will hold information about any particular petition.

It will contain the following fields:

    Title
  • Body (Petition description)
  • Goal (integer) – A number we are looking to reach.
  • Image
  • Petition duration (date) – A date until which this petition will be active.

Verify contact fields exists

We mentioned that we would like to collect the name, email, city and state of the petition signer; that means those fields should exist in the contact type. If they do not exist let’s add them:

  • Contact Name: (a name field)
  • Email: (an email field)
  • Address: (postal address field)

In the example above, the “individual” contact type already has both a name field and an email field. It also has a billing address field, but we will create another field for the petition signing address.

Creating an “petition signature” activity type

The next step is to create a petition signature activity type which we will store the information about the petition signature. We will create the additional fields:

  • Public display (whether the petition signer gives consent to display his/her name on a public list of petition signers)
  • Petition Reference (A reference field back to the online petition content)

Create a CRM Core Profile form

Now we have created all of the components that will store online petition data. We have a content type, a contact type “individual” and an activity type “petition signature”.

The last step in configuration will be to create a CRM Core profile form, which will essentially be “the petition signing form”.

There are a couple of things we would like to customize on the form:

  1. We’d like to make the submit button say “Sign”
  2. We do not wish to collect the entire address; instead we only want to collect city and state information.

We will visit these 2 issues in the “Additional Customization” section below.

Export the feature

Now it’s time to export everything we have done into a “feature” module.

Additional Customization

Now that we have our “feature” exported, we can now implement additional customizations. We will do the following:

1. Permission
We want to introduce a permission so that only certain user roles can view the petition signing form. In this particular use case we don't have a great need for a permission, since we would like to allow everyone including anonymous users to be able to sign our petitions. Since many other use cases will require it, though, we include it for completeness.

<?php
// crm_core_petition.module /**
* Implements hook_permission
*/
function crm_core_petition_permission() {
  return array(
   
'crm_core sign online petition' => array(
     
'title' => t('Allow online petition signing'),
     
'description' => t('Ability to use petition signing form on online peition pages'),
    ),
  ); 
}
?>

2. Customize UI
The aforementioned customization on the form needs to be performed. We would also like to show the petition form on the petition content itself.

<?php
/**
* Implements hook_node_view
*/
function crm_core_petition_node_view(&$node, $view_mode) {
  
   if (!
user_access('crm_core sign online petition')) {
     return; 
   }   
// let's embed the petition signing form on the online petition content itself
 
if ($node->type == 'online_petition') {
   
$crm_core_profile = crm_core_profile_load('petition_signing_form');
    if (!empty(
$crm_core_profile)) {
     
module_load_include('inc', 'crm_core_profile', 'crm_core_profile.forms');
     
$node->content['crm_core_petition_form'] = drupal_get_form('crm_core_profile_entry_form', $crm_core_profile);     
     
$node->content['crm_core_petition_form']['#weight'] = 999;
    } 
  }
}
?>

The above code simply embeds the petition signing form we have created earlier into the petition content.

<?php
/**
* Implements hook_form_FORM_ID_alter().
*/
function crm_core_petition_form_crm_core_profile_entry_form_alter(&$form, &$form_state, $form_id) {
 
 
$profile = $form_state['profile'];   // making sure we are on the correct crm_core_profile
 
if ($profile['name'] != 'petition_signing_form') {
    return;
  }  
// adding css class to the form for additional style customization
 
if (empty($form['#attributes']['class'])) {
   
$form['#attributes']['class'] = array('crm_core_petition_signing_form');
  }
  else {
   
$form['#attributes']['class'] += array('crm_core_petition_signing_form');
  }
 
 
// Change the form button value and hide some of the address components
 
$form['submit']['#value'] = t('Sign the petition');
 
 
$form['field_contact_address'][LANGUAGE_NONE][0]['street_block']['#access'] = FALSE;
 
$form['field_contact_address'][LANGUAGE_NONE][0]['locality_block']['postal_code']['#access'] = FALSE;
 
$form['field_contact_address'][LANGUAGE_NONE][0]['country']['#access'] = FALSE;  
}
?>

We also do some UI customization such as adding CSS class to the form and hiding parts of the address field we don't need (street, locality, and country blocks).

3. Misc.
There are other things we would like to do such as setting a default value on the petition signature activity.

<?php
/**
* Implements hook_crm_core_profile_activity_alter().
*
* We are just setting some default value to the crm_core_profile form in the activity data container
* the $form here refers to the $form['activity'] data container from the original crm_core_profile form
*/
function crm_core_petition_crm_core_profile_activity_alter(&$form, $profile_name) { 
  if (
$profile_name != 'petition_signing_form') {
    return; 
  }
 
 
// since we are embedding the online petition form in the content itself, we can get the content information
  // as well
 
$node = menu_get_object();
 
 
// we are just setting the reference (association) of the activity back to the petition content
 
$default_value = sprintf('%s (%s)', $node->title, $node->nid);
 
$form['field_crm_petition_reference'][LANGUAGE_NONE][0]['target_id']['#default_value'] = $default_value;
}
?>

All done in less than 100 line of code. We can now test our feature.

Reporting and more

Now let’s create a simple report to show how many people have signed a particular petition as well as all the petition signers for a petition. We will also create a block counter to show the number of people who have signed the petition.

We will be using views and views data export module to achieve our goal.

Now that we have a general report showing a list of petitions created online, let’s create the petition signer report for an individual petition.

We now have a pretty good report showing all the signers of a petition as well. We can also create a petition signer count block and place it on the petition content:

Lastly, let’s update our feature with the report and other new components created.

That’s it, now you have a fully working online petition feature that can be deployed on any Drupal website with CRM Core and CRM Core Profile enabled.

Take it one step further

Let’s suppose that the following additional requirements have come in:

  1. We also want to track the source of the petition signers. We want to know if they came from an email campaign, a paid search engine campaign, or some other source.
  2. Upon successful signing of a petition, we want the user to be redirected to a customized thank you page where he/she can forward the petition to a friend, spread the word on social media, or take another action on the website.
  3. Suppose that we would like to make the petition time sensitive so they can only be signed in a specific time intervals and they will automatically become unavailable after the time has expired.

How would you go about implementing these additional requirements? Post your ideas in the comments, and we'll be happy to discuss them with you.

AttachmentSize 67 KB
Oct 15 2012
Oct 15

Posted Oct 15, 2012 // 8 comments

Out with the Old

The Drupal Features module has always had a quirky user interface. I'm talking about the "New Feature" or the "Recreate" screens. In those screens you see the name, description and other general information at the top. On the right is a summary of what components/items are exported to the feature. On the left there is a Components drop-down selector. To add a new item to the feature, you first select the Component from the drop-down (like Fields), and then you click the checkbox for the Item you wish to add (like a specific field name).

Old FeaturesEach time you click a checkbox, an Ajax call is made to refresh the summary shown on the right. This adds the item you just selected to the summary, and also computes new "auto-detected" items that are also added. For example, when you select a Content Type, all of the Fields for that Content Type are automatically detected and added.

For years Drupal users have complained about this and suggested improvements. I've summarized the issues over the years into the following (probably incomplete) list:

  • Ajax callback whenever an item is clicked is slow and cumbersome. Makes it a pain to select multiple items.
  • Dropdown list of Components is poor. Prevents seeing more than one component at a time. New users don't initially know to select a component.
  • Summary of items included in the feature shown on the right mostly duplicates the information shown on the left by which checkboxes are enabled.
  • No way to filter items to just those that contain certain text.
  • No way to specifically exclude auto-detected items from being added to the feature.
  • Cannot distinguish between newly added items that will be exported from items that were already part of the feature export.
  • Options such as "URL of Update XML" are for advanced users and shouldn't be shown all the time.

The new 1.1 branch of Features attempts to fix or improve all of these issues.

In with the New

New FeaturesIn the new featuresUI-1.1 branch makes the following changes to the user interface:

  • The Ajax on the checkboxes has been completely removed. The Component Dropdown menu has been completely replaced with a set of collapsible fieldsets, one per component, shown on the right. To add a new item to a feature, expand the fieldset for the component you want, and click the checkbox for the item you want. The item will be moved down to the "newly included" list of items to be exported.
  • If you add an item that adds dependencies, the auto-detected items will be added to the export (in blue italic). To prevent an auto-detected item from being exported, simply uncheck the box.
  • Newly added items are shown in bold with a gray background to distinguish from items already part of the export.
  • A Filter box is shown along the top. Enter text into this box to only show items that contain the filter text. Components with matching items will be expanded automatically. Clicking the Clear button will remove the filter and collapse all component sections.
  • Advanced options are collapsed into a new Advanced section on the left.
  • If Javascript is disabled, a Refresh button will be displayed that can be used to manually refresh the list to show newly auto-detected items. When Javascript is enabled, this button is hidden since javascript is used to display the auto-detected items.
  • Items that are auto-detected and then unchecked are saved to the export *.info file a "features-excluded" items. Having these items in the *.info file allows features to keep them unchecked in the future so they are not automatically added.

Give the new UI a test drive by checking out the featuresUI-1.1 branch:

git clone --branch featuresUI-1.1 [email protected]:project/features.git

If you have any trouble, it's easy to switch back to the 1.x branch. Let me know what you think, or feel free to post to the issue queue http://drupal.org/node/1810134

Mike Potter is a Team Architect at Phase2 who loves to pair a solid technical solution with an intuitive client-focused design. Mike started his career as an experimental neutrino particle physicist before creating the first WWW home page for ...

Oct 05 2012
Oct 05

Episode Number: 

23

In this episode we go over the Drupal 7 Strongarm module and how it can be used to manage variables and configuration on your Drupal website. This episode looks at how the Drupal 7 Features modules can be used with the Drupal 7 Strongarm module to manage the exporting of the Drupal variables table.

In this episode you will learn:

  • An overview of what the Drupal 7 Strongarm module is and how it can be helpful when developing a Drupal site
  • How to use the Drupal Features module and the Drupal Strongarm module work together to allow easy exporting of variables

DDoD Video: 

Oct 03 2012
Oct 03

CRM Core is a tool for managing contact information within a Drupal website. It was designed to act as a platform, where developers can add small, useful applications on top of the core components to handle specific use-cases. It was also designed to be highly interoperable with Drupal so that people without any specialized programming knowledge could work with it.

CRM Core was launched a little over a year ago, and one of the most common questions we encounter is about creating a new feature to interact with the platform. Creating a CRM Core feature should not be a huge hurdle for anyone with a basic knowledge of how to work with Drupal. The process is pretty simple and should require minimal amounts of code; in fact, it's possible to create them without writing any code at all.

This blog post presents a step-by-step guide to creating CRM Core features within Drupal. It will demonstrate how someone can set up a site to collect information about contacts, create useful interfaces for interacting with the information that is collected, and build forms for collecting this information from the public. It also outlines how to create portable features for CRM Core that can be used across multiple sites, allowing people to build their own CRM systems to serve niche needs.

This exercise can be carried out by anyone with a fresh copy of Drupal, and can be completed in as little as 30 minutes. We have included sample code demonstrating all of the points in this exercise, in case you get stuck at any point or just wish to jump to the end.

What Are We Building

CRM Core is designed as a platform for building small, useful applications that add functionality to the system. The modules are designed with a fairly robust API to interact with, meaning a Drupal developer should be able to find lots of ways to hook into the system without much work. Developers are going to be building features, which should be familiar to most people with any kind of background with that module.

It's important to start off with a clear sense of what you are trying to accomplish. Stating the business case you are trying to capture can make all the difference in what you get out of building your feature. We suggest taking an approach where developers will start by building a small prototype that demonstrates what you want to accomplish, before going back to refine it over time using Drupal and CRM Core's APIs. This will save a lot of time by getting tools into your hands early and providing you with simple proofs of concept that can be efficiently built out into powerful tools through successive iterations.

In this case, let's say we are going to build a lead generation tool for tracking contacts who have come to the site and asked questions by filling out forms. In addition, we want to be able to manage leads by assigning them to specific users - our sales people - and ask them to follow up with each lead. It's pretty easy to assign further requirements from the get go, but this is a pretty simple list to get us started. What we are looking to get is a contact form for people to fill out, and an interface on the backend that allows people to see what leads have been submitted (and their status).

In CRM Core terms, we are going to be carrying out a number of simple steps to enable lead generation, focused on assembling a prototype that can be refined to make our new application very useful. To help you visualize the overall process:

  • Begin by installing Drupal and CRM Core.
  • Configure contact types and activity types for storing data.
  • Create a profile form for collecting information.
  • Customize the way information is handled in the system (optional).
  • Build a view to act as an interface for your data.
  • Export everything as a feature so you can encapsulate your code and share it with others.

There is very little in this list that basic site builders would find unfamiliar. The feature included with this message is an example you can look at in case you get stuck.

What You Need

To begin with, you need to install CRM Core and it's dependencies. The basic requirements for CRM Core are listed below, and there is not much configuration required for any of them to work. Using a fresh installation of Drupal, install and activate the following modules:

  • Views
  • CTools
  • CRM Core
  • CRM Core UI
  • CRM Core Activity
  • CRM Core Activity UI
  • CRM Core Contact
  • CRM Core Contact UI
  • CRM Core Relationship
  • CRM Core Relationship UI
  • Entity API
  • Entity Reference
  • Relation
  • Field UI
  • Image
  • File
  • Address Field
  • Email
  • Link
  • Phone Number
  • Fieldgroup
  • Name Field
  • Date API
  • Date Popup
  • Date Views

This may sound like a long list, but remember: a lot of these modules are simply field definitions, and some of them are things you would need elsewhere in your site regardless of whether or not CRM Core was installed.

In addition to the basic requirements, install CRM Core Profile (http://drupal.org/project/crm_core_profile). This module is important, it will allow you to create contact forms that can be displayed anywhere within your Drupal site for collecting information. We are going to use it in this example to create one form for capturing contact information, and it can be used over and over again to collect lots of information from your users.

Step One: Configure your Contact Types

To begin with, you will want to configure your contact types so there is a way to store information about contacts. This can be done through the web-based admin interface by going to Structure > CRM > CRM Contact Types, or through the following path: admin/structure/crm/contact-types.

Select the individual contact type and start configuring fields. There's not much to say about this page, administrators will configure fields for collecting contact data in the same manner he or she would for a content type. This page allows you to specify the information you are going to track about conations coming to your site. You can add an unlimited number of fields from this page, and you will likely come back to it at some point to set up more fields to collect about people.

For this exercise, make sure there are fields for name, image, email address, address, and phone number. These will be the basic fields we use to collect information from users in the site. Feel free to add additional fields, but they are not required to complete this exercise.

Step Two: Create an Activity Type

The next step is to configure an activity type that will be used to track information submitted by users. We are going to configure the system to capture leads, and to associate them with specific contacts so you can track them over time.

In case you are wondering, an activity type is simply a way of tracking action for a contact. In CRM Core terms, this is the basic way to track interaction with someone, it stores information about the interaction as opposed to information about the person. When you plan for a CRM Core installation, it's important to think about the ways you are going to want to track people and set up the appropriate activities to capture information efficiently. This is a page you will probably come back to each time you need to track something new about interaction with people.

Begin by going to Structure > CRM > CRM Activity types in the web based administrative interface, or simply by going to the path admin/structure/crm/activity-types.

From here, create a new activity type called "Lead" and create some fields for that activity type. There will be some default fields already configured. Leave those alone, and create some additional fields that will be used to capture information. For the purpose of this exercise, set up the following custom fields using the web-based administrative tool:

  • Status - to track the state of the lead
  • Assigned To - to track who is responsible for the lead. Use entity reference to associate the activity and a user.

Like contacts, activities can store any number of custom fields you need to effectively track information. You can associate any additional fields required as part of this activity type, and it can easily be expanded to capture other points of data over time. For right now, we simply want to know that leads are being acted on, and that someone is responsible for them. Save the activity and continue.

Step Three: Export the Activity Type to a Feature Module

A best practice with CRM Core is to export your customizations to features. On the one hand, this makes your new application portable, meaning you can share it with others and use it on multiple websites. On the other hand, it helps to keep your work organized and free from defects that can emerge over time. It's a good idea to export features early and often, and occasionally test them using another installation of Drupal.

Within the web-based administrator, go to Structure > Features and create a new feature called 'CRM Core Leads.' From within the components drop down, select the crm_core_activity_type option, and check off the box for Lead. This will create a feature that simply stores our new activity type. We will add additional information to it over time.

Export the feature and save it in your sites directory, preferably somewhere like sites/all/modules/features/crm_core_leads. Afterwards, return to the features page and make sure the new feature you just created is enabled.

Step Four: Create a crm_core_profile Form

At this point, your site has the ability to store contacts, and associate leads with them. The next step is to create the contact form that will be used to capture the lead and store it in the system.

is a module that builds forms to collect information about contact and activities. It's a very powerful tool for collecting information, and can be used to create any number of forms in your site that populate fields in contact and activity records. The CRM Core API can be used along with CRM Core Profile to efficiently handle very complex business requirements. The module itself contains many examples of how to write code for CRM Core Activities that can be used as templates for other modules.

In this example, we are simply going to use the out of the box components to create a new contact form, which will drive the creation of leads within CRM Core.

Begin by going to the Structure > CRM > CRM Core Profile in the web-based administrator, or directly to the path admin/structure/crm/profile. This will present you with a list of all profile forms that are configured for your system. Click the link to add a new profile at the top of the screen.

Start by giving the new profile the name Lead Inquiry. Note the machine name being generated next to the title of the form. Programmers will use this when they need to reference the profile from Drupal's API, and we will show you an example of how to do this in this exercise.

You will be presented with a screen that allows you to select the fields you want to use to populate the contact record and the activity. Select the following fields from the Contact Record:

  • Name
  • Email
  • Phone Number

In addition to the basic fields, you can provide some information to help users access your new profile through this screen as well. Optionally, you can provide a path to get to the form, which will allow public access to the form from the specified URL. You can provide a redirect path to take users to a new URL after submitting the form. You can enter a message to display when users successfully submit the form. You can also enable a block to display the form within your site. These are not necessary for the purposes of this exercise, but may help you to visualize the results.

Below, in the activity information section, use the select box to select the Lead activity type. The screen will refresh with a list of fields. Select the description box, this will simple be used to collect some notes about the activity.

Click the create button. At this point, you will have a form that allows you to collect leads within your site. You can see it listed on the CRM Core Profile screen in the web-based admin screen, and can browse to it via the path specified in the configuration screen.

Step Five: Add Customization in the Feature Module

This step is completely optional. If code makes you all upset, skip to step six.

One of the challenges that comes from creating new activity types is identifying individual ones in the system. Over time, contact records can generate a lot of activities. It's important to lay out activities n a meaningful way, in order to ensure you will be able to understand what has happened with a contact over time.

We need to do some scripting to people can easily identify a lead in the system. As part of this exercise, we are going to add some code to the feature module we created for our new lead generation tool, which is going to add a distinct name for each lead that comes in.

Open crm_core_leads.module from within your feature and insert the following code:

<?php
/**
* Implements hook_crm_core_profile_activity_alter
*/
function crm_core_lead_crm_core_profile_activity_alter(&$form, $profile_name) { 
  if (
$profile_name == 'lead_inquiry') {
   
$form['title']['#value'] = t('Contact Form Lead');
  }
}
?>

In Drupal terms: we are implementing a hook which will override and change the name of the activity to "Contact Form Lead" when it is being associated with the contact record. Every new lead associated with the contact record will have the same name, "Contact Form Lead." Optionally, if you wanted some additional control over the name, a developer could include any other information from the profile form in the title (for instance, a date or the name of the contact). For practical purposes, this is all that is needed.

It's important to note that this example does not use CRM Core's API or any special code outside of Drupal's APIs. A developer does not really need to understand anything specific to CRM Core in order to make this work, but it helps to know why are doing it. There are many other ways to extend and customize this feature module, but the above is all that is useful for this exercise.

Go ahead and export your feature again at this point. While it's not strictly necessary, it's a good idea to export a feature any time you have added new code or changed any settings associated with it, for the reasons stated previously.

Step Six: Add Some Administrative Screens

At this stage, we have our contact records configured, an activity type for tracking information, and a profile form for collecting information. We have customized the feature to carry out some basic operations that allow users to identify their leads more easily in the system. The only thing really left is to give people a simple way to interact with their leads by creating an interface to track them.

As part of this exercise, we are going to create a screen within our feature that allows people to lookup leads, change their status, and assign leads to specific users within our system. The simplest way to create such an interface is the views module, which will be used to present lists of leads and operate on them within the site.

Create a new view with the following basic setup:

  • Name the view 'CRM Core Leads.'
  • Use select Activity Types from the show select menu, and select activity types of 'Lead.'
  • Check the box to create a page for the view, call it 'All Leads,' and give it a path of 'all_leads'.
  • For display format, have it display a table.

Press the continue and edit button. On the resulting page, add fields for the contact and the activity type as part of this exercise. Views will give us a list of fields referencing the activity itself, and we are going to add relationships to get information about the associated contact.

Within the advanced menu, click the link to add a relationship. Check the box for 'Entity Reference: Referenced Entity' and apply it to all displays. On the resulting screen, just select the option to apply it to all displays. This will allow you to add fields to the view for the contact associated with the lead.

From here, add fields to the view. For this exercise, we are going to add the following:

  • Name (from crm_core_contact:individual)
  • Email address (from crm_core_contact:individual)
  • Status (from CRM Activity)
  • Assigned To (from CRM Activity)
  • Date (from CRM Activity)
  • Edit Link (from CRM Activity)

With these fields in place, turn off the page and save the view.

This view can be customized to include any fields you are looking for. Just remember, the relationship is important, it is what lets you reference content from the actual contact record. You can use this along with aggregation to get some really interesting data into your interface.

Once your new view is created, save it along with the CRM Core Leads feature, and export the view.

Step Seven: Extend Your Feature

This exercise provides an overview of the basic method for creating a new feature for CRM Core. This feature provides an interface for users to look at information related to a contact, tracks leads along with status and assignment, and stores information in manner where it can easily be identified within the system.

From here, it's up to you to extend it to handle the specific business rules for your website. There are a lot of ways to go from here, and you may want to consider some of the following as paths for how to make the site awesome:

  • Securing the view, assigning the appropriate permissions to make sure only the right people can access it.
  • Implementing views bulk operations, to allow you to modify a bunch of leads all at once.
  • Implementing exposed filters within the view, to limit the number of records returned or for only viewing leads assigned to a specific user.
  • Implementing additional views to show how many leads have come in in a given month.
  • Implement filters within the views to ensure users can only access their own leads.
  • Add triggers around the submission of the profile form to receive emails whenever you receive a new lead.
  • Associate contact records with users in your Drupal site to allow people to self-maintain their contact information.
  • Associate your CRM Core profile forms with other content types, in order to allow in-line submissions.
  • Create organic groups to manage large lists of contacts.
  • Repeat this exercise for other types of interaction with users besides creating leads.

Take the time to consider how long it took to carry out this exercise. In general, adding a new feature to CRM Core is the sort of activity a developer can handle in less than a day to get to a prototype stage. A best practice around CRM Core development is to build features quickly before going back to refine specific interface and business rule requirements. Something we like to say at Trellon, no one ever knows exactly what they want until they have their hands on it.

A word of advice: take features seriously. At some point, we are going to set up a features exchange for CRM Core, to allow people to share the features they create with the community. For right now, it's helpful for developers to maintain a stock of the features they have created to keep handy for when they are building sites. Trellon has a set of features for event management, membership, claiming profiles, controlling access to physical resources, donations, store purchases and more. We plan on releasing them along with the features exchange, and will be happy to share them before it is ready if you ask us nicely.

Sep 10 2012
Sep 10

Hello there Daily Dose of Drupal faithful! Today we have another episode of the Daily Dose of Drupal brought to you by codekarate.com. Today is episode 4 and we are again going to look at the Features module but this time we are going to do a couple of things. First we’re going to see how the Drupal Diff module can fit in to the mix and we’re also going to talk about how this might work if you have a Drupal development and a Drupal live site.

So as you can see right where we left off last time with the Views module or excuse me, the Drupal Features module we created, working and we’re going to create or excuse me; change the view again and in this case we are going to go ahead and just pick one here; we’ll do a … we’ll go ahead and do a Line Chart this time.

So we’re going to apply that, save it and then we’re going to take a look. As you can see we now have a Line Chart which is different than the Test 1 site. Again; it is still just the regular old Pie Chart that we created the first time. In this case let’s imagine that the Test 2 site is our Drupal Development site and we’re going to be pushing out our Features module onto the test site which is over here and that will be our Drupal Live site.

So we’re going to first take a look at our Feature and see that on our Test 2 Development site it is overwritten. So we’re going to download the Drupal Diff module. So I’m using Drush to download the Diff module onto the Test 2 site, I’m also going to enable the Diff module using Drush.

So all I did was download the Drupal Diff module and enable it. Now if I refresh this page you can still see the Drupal feature is still overwritten, I can go into that and there’s actually the ability to review the overrides. So it actually compares the differences between what is the default which is the Drupal Features Module Code and what is in the database.

So you can see it’s now going to be a Line Chart because that’s what we set it as and we could do two things at this point; we could go ahead and recreate the Drupal Features module the way we discussed the last time which would recreate. this is going to then download the .tar file which we could then drop in over top of the existing code and get it to update but as you can see that seems a little complicated.

All we want to do here is we want to update the code that’s already here to represent what we have in our database and Drush allows us to do that very easily. So we’re going to go ahead and do Drush Features update and the shorten version is drush fu monthly_earning and we will run that and say the module already exist, do you really want to continue because this is actually going to update the code.

So now the code is updated we can go back here and refresh and you can see it’s now at the default status. So now that we have the updated module on the Drupal Development site; what we’re going to do is we’re going to actually drop this into the test.codekarate.com site which is going to act as our Drupal Production site or Live site in this example.

So I’m going to hop over to the Test 2 module’s directory and I’m going to just copy this monthly_earning module, I’m going to paste it over in the module’s directory on the test.codekarate.com site.

So after that we drop that in I am going to go into the module’s page and I could enable it from here … the Monthly Earning, I can also enable it from the Features page just to show this as an example and we’ll go ahead and save that and this is on our … what we consider to be our Live site for this example and it’s taking a little bit of time here but it should be … reloading here pretty shortly.

And even though we have the Drupal Content Type and the Drupal View on this site, it’ll still be okay, it’s going to just install the Features module that we created and it will then be able to revert this back to what is in the Drupal Features code. So you can see it’s overwritten, it’s saying that the view is overwritten because we made a change in the module on the Test 2 site which is the Development site.

What we’re going to do is we’re going to go ahead and revert this. Anytime you make a deployment from a Drupal Development site to a Drupal Live site you generally going to have to revert your Drupal Features module so we’ll revert this and we are going to go to that Monthly Earnings Report view and we will see there’s now a Line Graph with our 2 data points on it. One thing … as I mentioned before you always going to need to revert your Features module when it gets to the Live environment and you can also do this through Drush so if there was a change you can go ahead and do drush fr for Drush Features Revert, whatever your Features module name is, in this case monthly_marning. So it's drush fr monthly_earning

You’re also going to want to keep in mind that the reason you do this … the reason you have the Features module to deploy between different environments is so that you don’t actually have to touch the View or the Content Type in your Drupal Live environment because you’re just relying on the Features module to do the work. If you need to make a change we would come in to the Development site, make the change and the reason we’re just changing the type of graph is because it’s an easy change to show how it works but you can make changes to the content type or anything else that you exported with the Feature.

We go into the Feature module, we can confirm that it’s overwritten, we go ahead and do a Features update, this is just to show how deploying it multiple times worked, we are going to copy this over and in most cases; keep in mind that you’re going to be using not just a copy and paste like I am right here. You’re going to be using most likely a version control system like Git, BZR, SVN or some other type of version control system to actually move this between different environments.

So now that we’re updated we’re going to go to our Features module on the Live site and you’ll see it’s overwritten. So I’m going to go ahead and go into the test.codekarate.com site and show you that you can do a drush fr monthly_earning and this is going to show you that it’s going to revert the view, after you revert it go back, refresh, you’ll see that it should have been reverted … something apparently didn’t get reverted right, try that one more time once; interesting; well it’s not saying that it actually reverted it but let’s go ahead and check, I’m just trying to revert it this way just to see if this will work.

Okay so apparently there’s an issue so we’re going to do some troubleshooting so I’m going to go ahead in Drush download the Drupal Diff module and enable it again to see what is causing this to not work correctly. Well as soon as I went to actually see the difference it seems to have corrected itself.

One of the things you’ll notice is every once in a while with the Drupal Features module sometimes your Content Types or views will get into a rebuilding status, I don’t know if that’s exactly what we saw here but sometimes it takes a few seconds to let it refresh. So I’m guessing that was the case, I reverted it but it did not actually show as a reverted status.

You can see now it’s the Bar Graph as it should be. If I go back in to the Features module it’ll show that it’s in the default status. So that’s it for today, we’re not going to worry about that little issue, I think it seems to resolved itself and next time we will cover something besides the features module. So tune in tomorrow and we will go over something different. Thanks for watching the Daily Dose of Drupal, until next time.

Sep 08 2012
Sep 08

Hello there Drupalers and welcome to another episode of the Daily Dose of Drupal brought to you by codekarate.com. This is episode 3 and today we’re going to continue looking at the Features module and it’s going to continue on what we’re working on yesterday.

So if you haven’t seen yesterday’s episode on the Features module, you may need to take a look at that first. We have our fresh Drupal 7 Installation here and we’re going to start by downloading some modules so I am going to hop on to the command line using Drush, I will download a few of the needed modules; so I’m going to download the Views, Views Dataviz, Features, Ctools and Date modules.

So run that Drush command and that will download those modules and now that’s finished up I will hop over here to the actual files, the modules directory; you can see that those modules are now there and I have also dropped in the monthly_earning.tar file that we created yesterday.

So I’m going to extract that features module here and you’ll see that the module is now extracted, I’m going to get rid of this .tar file, we no longer need that and I’m going to hop into the modules page, if I scroll down to the bottom you’ll see that in the Features section there’s a Monthly Earning module and if you look … there’s some dependencies here; one thing you’ll notice that’s missing … that we missed yesterday was the Views Dataviz module and since this is a standard Drupal module for the most part, we’re going to go ahead and add that dependency right in the .info file.

So I’m going to go ahead and open up that .info file, you’ll noticed that if you ever looked at any .info files before, it’s pretty similar, if I’m going to add the Views Dataviz module there, save that and I will refresh this page, scroll back down to the Monthly Earning module and you’ll see that Views Dataviz is now in the list of dependencies. I’m going to go ahead and turn this module on, this is going to catch all the dependencies and make sure they’re all turned on, so I’ll hit continue.

The other thing I’m going to do is go ahead is turn on the Drupal Views UI module so we can actually take a look at the view and now we will take a look and see that the Drupal Features module we created yesterday with the Content Type and the View is now available on this test2.codekarate.com website. So you’ll see there the Monthly Earnings Content Type, if you go into the views you’ll see the Monthly Earnings Report View and if you go into Features you’ll see the a Monthly Earning feature, this state or the current status is set to default and we will go over what that means here in a second but let’s go ahead and add some content to this site; so we’re going to start with the July 2012, let’s say 1,000, start also in August, go 1,500 and then we’ll do one more this time; and we’ll do September and we’ll do this 1,750, go ahead and save that one and we will now go to that monthly report and make sure that it is in fact working.
So we go to the Monthly Earnings Report, we’ll go ahead and just ignore this PHP Notice for now. There’s a Monthly Earnings Report, it’s the Pie Chart, we will compare this to yesterday’s example on the test.codekarate.com Drupal site and you’ll see that they’re different but just using the same Content Type and same Views across both.

So now what we’re going to do is we’re going to go ahead and change on the test 2 site, I’m going to go ahead and change that View and change the Report to be a Column, we’ll make this a Column Chart instead of a Pie Chart, save that and we will go back to the Monthly Earnings Report and you’ll see now we have a Column Chart. If we go back into Structure and go back to Features you’ll see that it is now in an Overwritten Status and what this means; it means that the Drupal Database configuration that contains the Drupal Content Type or the Drupal View has changed and is no longer the same as what is in the monthly_earning.module file or excuse me; the whole module … the whole Features module as a whole.

It means that the Database is in fact different, meaning that you made a change on the site that’s not represented in the code of the module. So if we go ahead and click on Overwridden it will show that the Views file is overwridden, if we go back we could recreate this if we wanted these changes to be included in the module and you’ll noticed that all the checkboxes that we had yesterday are still there, you hit Download and you’ll have a fresh new copy that’s slightly different of your new module that will have the Column Chart.

So this will download the .tar file, you could drop in to another site and this module would then have Column Chart rather than the Pie Chart. What you can also do is you can revert this back. So if we no longer want the Column Chart we want to in fact go back to the Pie Chart version, we go ahead and revert and what this is going to do is that it’s going to update the Drupal Database to represent what you have in your actual code of the Monthly Earnings module. So we’ll go ahead and revert that and you’ll see as the page refreshes it is back to the Pie Chart.

Well that’s really all there is to show today, hope you learned a little bit more about the Features module and tomorrow we will pick up where we left off and we will continue learning more about the Features module and how it can be use in deployments across Drupal sites.

So for instance if you have a Drupal Development site and a Drupal Live site and you want to move code across these different environments I’m going to show you a little bit more information on how that works using Drush and we’ll dig to the Features module a little more since there’s quite a bit to learn still.

Until next time, thanks for watching the Daily Dose of Drupal and if you like what you see you can follow me on Twitter @smthomas3 and you can also check out my other blog posts at codekarate.com. Thanks for watching.

Sep 06 2012
Sep 06

Hello there my fellow Drupal developers this is the Daily Dose of Drupal, Episode 2. Today we’re going to be talking about the Drupal Features module; the Features module is useful for a few different use cases but the first one we’re going to talk about is anytime you want to build something and re-use it across multiple Drupal websites; so this could be a blog, an image gallery or really any configuration of content types of views and other “features” that you may want to use across multiple Drupal websites and that’s going to be what we’re going to go over in this episode.

In the next episode we’re going to go over how this can be used to move this configuration across multiple environments. Let’s say you have a development and a live environment, you make a change to a content type or a view on the development environment, and then you can use a Features module to roll those changes up into the live environment. But we’ll go ahead and get started here and as you can see I used Drush to download the Drupal Features module and then I enabled the Features module so it should be there on our site and if you’re a Drupal developer and you don’t know what Drush is, you should definitely look into it as it will help you and just make your life easier.

So we’ll go ahead and we’ll check to make sure that the Features module is in fact installed, which it is and we’re going to use the content types and views that we created in the previous Daily Dose of Drupal, so I have a content type called Monthly Earnings and I also have a view called Monthly Earnings Report.

So we’re going to go ahead and go under Structure, click on Features and here’s a list of any features that you have installed on the site, we don’t currently have anything here so we’re going to click on Create Feature, we’re going to call this Monthly Earnings, I’m going to give it a description, you can select which package you want, you can give an optional version or the URL of the Update XML and that’s if you have this features hosted on a feature server and you’re going to be providing updates, we’re not going to worry about that and now we go through the different components. So for instance we’re going to start with Content Types; we want to export our Monthly Earnings; if there’s any dependencies of modules that are needed you can see that over here it already picks a lot of them for you and most of the time it should be pretty much automatic.

For instance; the Date module, the Features module of course and a few other dependencies that are needed. You then can select the fields so we’re going to select the two fields on the Monthly Earnings Content Type; the Month field and the Amount field, we’re going to go ahead and we do not have any Image style, we’re not going to be exporting any Manual Links or Menus, we’re going to skip the Permissions and the Roles as well as the Filter Formats and we’re going to go directly to the views. So we’re going to click on the Monthly Earnings Report View and we are going to go ahead and download this feature. As you can see I now have this monthly_earning.tar file that has just been downloaded to my computer.

So I’m going to go ahead and open that up; you can see that there’s a couple of files in here and basically what this does is it creates a module for you that you can then drop in and install on any Drupal website and this contains all of the code; so once you turn it on another sire you’ll have the same set up and the same configuration that you currently have.

So as you can see this is useful for a wide variety of things; if you build a lot of Drupal client websites and you intend to rebuild the same things like maybe it’s a View Slideshow and you want to reuse that slideshow on multiple sites, you only have to build it once, export it as a Feature and drop it in wherever it’s needed. Well it was short and sweet this time on the Daily Dose of Drupal and we’ll be back tomorrow with another video for you. Thanks for watching.

Aug 15 2012
Aug 15

In this lesson we cover how all over the configurations we have learned using Display Suite are able to be exported to code. This video shows how to do this using CTool but can also be done with Features as well.

Aug 06 2012
Aug 06

The popular Features module is the current king of the hill when it comes to bundling up Content Types, Views, and other custom configuration data for reuse on Drupal projects. Sometimes, though, a Feature needs site-specific tweaks before it's ready for prime time. Changing the API keys for external web services like Google Analytics and Disqus, for example, can be done using those modules' native configuration screen. But if your Feature module is consolidating the configuration work, wouldn't it be great to consolidate the settings forms, too? That's where Configuration Builder comes in. It allows you to build custom Drupal settings screens that can be exported and stored in a standard Feature module.

Screenshot of the Config Builder in action

Creating a new configuration screen, or altering an existing one, is clean and simple. Site builders can choose what URL their config screen will live at, as well as what permission or role will be necessary to access it. Config Builder leverages the powerful but little-known Form Builder module for the meat and potatoes work of designing the config form itself. Drag and drop addition of new form elements and re-ordering of existing ones makes things fairly straightforward; if you've ever used the WebForm module, it's leveraging the same interface tools.

By default, the forms that you've created will simply save their settings like a standard Drupal system settings form. It's up to you to write code that does something with the values. However, if you manually set the names of the different form fields to match the names of existing settings fields on other Drupal configuration pages? Voila! Your custom configuration form will begin loading and editing the same values. This means that you can create consolidated configuration forms that control specific important settings, like the Site Name or the Google Analytics API Key, without forcing users to hop from one screen to the next.

Once that's done, the custom settings forms can be saved and exported into a Feature just like your content types, Views, or custom site variables. If you'd rather bypass all the importing and exporting, Configuration Builder can also output the form you've designed as a standard set of Drupal hook implementations that can be pasted into a custom module, with no outside dependencies.

Screenshot of a configuration builder screen, exported to code

Configuration Builder may be overkill for developers who are used to slinging around custom settings forms and are comfortable embedding them in Feature modules. For site builders who want to tide up their own features, or developers working on larger multi-site platforms that need cleanly encapsulated and overridable settings forms, this module could be just what the doctor ordered.

*/
Jun 27 2012
Jun 27

If you're serious about Drupal development, you probably use Drush and Features. If you do use Drush and Features, you will likely have caught yourself wishing to the Drupal Gods for the ability to automatically increment or set a feature's version number when updating it.

Well wish no more! The issue was actually created a while ago but just recently got implemented and comitted. It is now available in the Features 7.x-1.0-rc3 release!

There are 2 new options available for the features-update (fu) and features-export (fe) commands: version-set and version-increment.

1
2
3
4
56
7
# Update (re-export) the "foo" feature and set its version number.
drush fu foo --version-set=7.x-1.0-beta1
 
# Update the "foo" feature and automatically increment its feature number.'
# It works with alpha, beta and rc versions too!drush fu foo --version-increment
# foo's version becomes 7.x-1.0-beta2

That's it about it, hope you enjoyed!

Now go increment all your feature's version numbers, just because you can! :)

Mar 21 2012
Mar 21

Posted Mar 20, 2012 // 5 comments

Overview

In our first installment (A New Paradigm for Overriding Drupal Features) I presented a new sandbox module that allowed you to override Field Settings from existing Features. In the second installment (Features and Overrides - Part Deux) I presented the Features Override 2 sandbox to handle all types of Features. In this final installment I will present the new Features Override 7.x-2.0-alpha1 module release that works with the new 7.x-1.0-rc1 release of the Features module to finally solve the problem of Overrides.

The Problem (revisited)

As a quick review, the problem we are trying to solve is dealing with site-specific changes to existing Features. The Drupal Features module allows you to capture configuration data, such as entities, fields, variables, views, permissions, etc into code modules.  These code modules can then be placed into version control, enabled and disabled, or used on a separate Drupal installation to provide the same feature.

In many cases, a Feature is developed for a generic site (or Distribution, such as OpenPublish) but needs to be slightly changed for the specific site you are developing. If you change the base distribution feature, it will be hard to upgrade to a newer version of that distribution feature. What you really want to do is just capture your changes to a site-specific "Override" feature and leave the original distribution untouched.

The Final Solution

The solution was a community effort combining the original Features Override 1.x module along with my Features Override 2 sandbox along with an experimental version of my sandbox created by hefox. The result is the 2.x release of Features Override (alpha1).

Based on community feedback, Features Override still uses existing Drupal "alter hooks" whenever possible, rather than changing the rendered exportable output. Although the original sandbox showed it was possible to achieve any override by added an alter hook to the exported code, it turned out that these alter hooks mostly existed already and just needed to be handled in a more general way. The new Features Override module maintains the easy user interface from the previous sandboxes.

New Features Release

To achieve a seamless Override solution, Features itself needed several patches. These included bug fixes to current ctools-based Features and the ability for a Feature component to specify the name of a custom alter hooks. All of these needed patches have now been rolled into the new 7.x-1.0-rc1 release of Features.

In addition to bug fixes and support for Overrides, the new release of Features also adds some new functionality:

  • In the list of Features, each Feature name now links to the view of that exported feature (for admins)
  • A new drush "fc" (feature-components) command can be used to list components matching a wildcard pattern.
  • The drush "fe" (feature-export) command uses the new component wildcard patterns and also replaces the previous "feature-add" functionality.
  • Conflicts with disabled features are less emphasized in the feature listing.
  • Package name for a feature can now be changed in the UI.
  • Exportables can now define their own "alter" hook name (for Override support) as well as write different code to different files.
  • Provides a stable and supportable module for Drupal 7 (no longer Beta!)

Features Override 2.x

The alpha1 release of Features Override defines two new types of component exportables. The first allows you to export all of the changes (add/deletes/changes) to an existing component:

Override_screen1

The new "View" button will display a popup list of the changes to the specific component.

The second type is for advanced users and allows specific line-by-line control over which changes are exported to the override feature:

Override_screen2

Clicking the Refine button expands the component to show each add and delete. You simply check or uncheck the box to include the change in the override exportable.

A new "Review Overrides" screen is also provided to display all of the changes with better context information than the previous "diff" display. Rather than creating a new tab as I described in the previous blog, the existing "Review Overrides" tab is used. The previous "diff" information is still included at the bottom if you have the Diff module installed. But even without the Diff module, the Features Override module will provide a much more useful display of what has changed on your site.

Override_screen3

Notice the new upper section that displays all of the relavent changes more concisely and with the name of the view and name of view display being changed compared with the raw code "diff" shown below.

Bonus Level!

If you are still reading this, then you deserve something extra: I have attached a pdf copy of my Features & Overrides slides from DrupalCamp Maryland. Enjoy!

And thanks to everybody who attended the Features BoF at DrupalCon Denver on Tuesday. Great to see the interest in Features & Overrides and to put faces with some of the names in the issue queue.

Conclusion

The new Features Override module has been designed to be easy for site builders to use. It now works with the released version of Features. No more special patches are needed. You can start playing with Features Override on your real web site projects. It's possible that not all feature type will work because we now rely upon existing alter hooks. However, the API exists for each feature component to define it's own alter hook. If your favorite feature component is not supported, post to their issue queue and ask them to support Features Override -- it's very easy for them to do now. With working support for Views and CTools-based features, Features Override should finally start to get the kind of usage and support that it deserves. It's a very important tool in the Drupal site-builders toolbox for building complex sites built upon distributions and custom features.

Mike Potter is a Team Architect at Phase2 who loves to pair a solid technical solution with an intuitive client-focused design. Mike started his career as an experimental neutrino particle physicist before creating the first WWW home page for ...

Jan 27 2012
kwu
Jan 27

Using UUID and UUID_FEATURES modules Part 2

Posted on: Friday, January 27th 2012 by Keen

Last time I posted a blog: "Using UUID and UUID_FEATURES modules Part 1" where I explained the basics of using UUID module to generate identity values.
The next thing you'll want to do is to use it in the real feature export components. Here is an example how we use it:
One of the projects I was working on needed locale languages support in taxonomy terms. Unfortunately, the exportable taxonomy component uuid_term provided by uuid_features module does not support i18n and is not exporting language & translation set fields.

The way these two fields are stored in the database are:

Language Code of taxonomy term

Table: term_date
Field: language

Translation set ID is a group id that linked translated
taxonomy terms together, generated by i18ntaxonomy_next_trid()

Table: term_data
Field: trid

For more information, please check out i18n module.

And here are the steps to make them exportable with taxonomy terms:

Step 1:

Include uuid table definition for trid field in uuid_features.install

/**
* Implementation of hook_schema().
*/
function uuid_features_schema() {
return array(
'uuid_i18ntrid' => uuid_table_schema('i18ntrid', 'trid'),
);
}

Step 2:

Update uuid_term_features_export_render () function in includes/uuid_term.features.inc
Add language code and trid fields to export.

Replace these lines:

// Whitelist of term properties.
$props = array('name', 'description', 'weight');
foreach ($props as $key) {
if (isset($term->$key)) {
$export[$key] = $term->$key;
}
}

By:
// Whitelist of term properties.
// add language and trid fields to export
$props = array('name', 'description', 'weight', 'language', 'trid');
foreach ($props as $key) {
if (isset($term->$key)) {
$export[$key] = $term->$key;
}
}
if((int)$export['trid'] > 0) {
//if trid field is not empty, replace it with trid_uuid
$export['trid_uuid'] = uuid_get_uuid('i18ntrid', 'trid', (int)$export['trid']);
//if trid _uuid value not yet exists, generate a new one by using uuid_set_uuid()
if(!$export['trid_uuid']) {
$export['trid_uuid'] = uuid_set_uuid('i18ntrid', 'trid', $export['trid']);
}
}
unset($export['trid']);

Step 3:

Update uuid_term_features_export_rebuild () function in includes/uuid_term.features.inc
We will translate trid_uuid back to trid by uuid_get_serial_id() and i18ntaxonomy_next_trid()

Search this line in uuid_term_features_export_rebuild()

$ret = taxonomy_save_term($data);

And insert following codes before this line:

//process trid field
if($data['trid_uuid']) {
//try to get trid by trid_uuid
$data['trid'] = uuid_get_serial_id('i18ntrid', 'trid', $data['trid_uuid']);
//if trid does not yet exist, generate a new trid by i18ntaxonomy_next_trid()
//and set its uuid by trid_uuid
if((int)$data['trid'] == 0) {
$data['trid'] = i18ntaxonomy_next_trid();
uuid_set_uuid('i18ntrid', 'trid', (int)$data['trid'], $data['trid_uuid']);
}
unset($data['trid_uuid']);
}
else {
$data['trid'] = 0;
}

Now if you recreate those features containing taxonomy terms. You will get language and translation set fields exported correctly.

Modifying a contributed module itself is not suggested, and the modification made here is just for demonstration. You may clone the uuid_term component and modify it for your needs to create your own features integration module.

Thanks for reading.

Jan 25 2012
Jan 25

I've been getting inquiries in IRC and in the issue queue about a module I blogged about a few days ago. The blog post I wrote may have seemed that the module we are working on is duplicating the features module and that we should instead work on the features module. I want to clarify our intentions.

The configuration module isn't a replacement for features. The vision is that they could work together. Features currently serves two purposes, 1) to group configuration together to satisfy a certain use-case, and 2) the actual export and management of configuration into a "feature" module. Features module is an awesome module when using it for what it was built for, creating KIT compliant features. The reality is most people that use features probably haven't even read the KIT specification.

Hypothetically, let's use the features concept with the concept of a bakery. Lets say a baker has a feature called "Birthday Cake". This "birthday cake" feature has several ingredients to make a birthday cake and one of those ingredients is called flour. The baker has another system that manages ingredients called configuration. Configuration manages the flour ingredient and makes sure it always stays the same type of flour.

Flour can go in a lot of recipes, not just in birthday cakes, so this ingredient shouldn't be owned by birthday cakes, flour should be free to be in any food item without creating a dependency of needing to bake a birthday cake too. If the birthday cake feature managed the flour ingredient, the baker could never bake cookies with his "Cookies" feature, without also baking a "Birthday Cake". If flour is managed by the "Birthday Cake" feature and the baker decides to never bake birthday cakes again for his bakery, flour no longer exists, because you only have flour if you bake birthday cakes.

If one of the ingredients that configuration is managing ever changes the meaning of flour to mean "spelt flour" rather than what it was, "white flour", the recipes (features) would need to be notified by the configuration system saying that flour is different now and your recipes are now different. This is how they work together.

Ingredients shouldn't care what recipes use it, and recipes shouldn't manage and own individual ingredients exclusively. The ingredients need to be managed by a different system. Ingredients are configurations and recipes are features. Recipes use ingredients, and features could use configuration.

This module simply takes the configuration part out of features, and provides a new workflow for managing configuration, more along the lines of what CMI is going to do in Drupal 8. The vision is the features module could evolve to use this module once this module matures over the coming months. When Drupal 8 comes out, features will need to evolve to not do configuration management any longer anyways, all this will be built into core. Drupal 8 will probably not be released for a while, if it follows the same development cycle as D7, hence the reason why this module was written, to incorporate Drupal 8 configuration management ideas in Drupal 7. Since Features, in a sense, already does configuration management, we used a lot of features module code to build this module.

As CMI progresses and more code is committed for Drupal 8, it's possible that this module may start looking like a back port of CMI and less like a duplication of features module.

Either way, features module will need to evolve eventually.

Features module is a great module when using it for what is was built for, creating KIT compliant features. It's once you start to depart from it's intended use, that you begin to find its limits.

Jan 23 2012
Jan 23

At ActiveLAMP, we have always been a big proponent for putting all configuration for the sites we work on into features. Much like everyone else in the Drupal community that uses features module, we figure out what configurations belong together, and create a feature to group these configurations together. Do these configurations together satisfy a certain use-case? Sure they do, for the particular site that we created it for, but for the most part, the feature really isn’t reusable on other sites unless we build another site that has the same exact requirements that this feature contains. In reality, we don’t really create reusable features that we can then use on other projects, because the projects we work on are just too different to be able to do this.

The features paradigm works great when you’re working on very similar sites, or even a distribution like Open Atrium, but not so much when working on many different sites that have nothing to do with each other, and many different requirements. When you really get down to it, we really use features module to manage configuration for the specific site we’re working on so that we can simplify deployment to dev, staging and production; we don’t use features to create configurations that satisfy a certain use-case that’s usable on other sites. In fact, I believe many of us in the Drupal community have become so accustomed to using features for configuration management and deployment, we just glaze over why Features module was really created -- to create a collection of Drupal entities which taken together satisfy a certain use-case (excerpt from features module page)

Don’t get me wrong, I love the features module, but I have to admit that I’ve run into my share of issues using features module for configuration management and deployment. Fortunately others in the community have ran into these issues too and have released modules such as features override, features plumber, and Features Tools. Not to mention entire workflows have been created around how to use Features to manage configuration for deployment that don’t even come close to creating KIT compliant features. Features module is really being misused, it’s not being used to create features, it’s being used to manage configuration and deployment.

Several weeks ago, after having multiple conversations with Alan Doucette (dragonwize), of Riot Games, this paradigm shift hit home for me. I had been using features module for configuration management and deployment so long, that I didn’t even think twice that I wasn’t using it for its intended purpose. I also realized that I had a tool belt full of work arounds to make features module kind of work for configuration management and deployment. There are a number of issues that you can run into using Features module for configuration management and deployment. In future blog posts I’ll elaborate on what specific issues we have run into.

After my discussions with Alan I was tasked to create a module just like the features module, except without the features part of it. We still think the features idea is a great idea -- to have a group of configuration to satisfy a certain use-case -- but we don’t think features module should be the tool to export and manage configuration. Our vision is that features evolves into using this configuration module to group configurations into a feature, but not actually own the configuration in a "feature" module.

Over the past few weeks I’ve been rewriting the features module without the features part of it. I’ve also taken a some concepts from the configuration management initiative, specifically the concept of the "activestore" and "datastore" architecture. This module is currently in a sandbox, as we’re hoping to get the namespace of an abandoned project. This module is definitely a work in progress, but we’re already using it on a couple production sites to work out the bugs and workflow. We want to get the community involved to hopefully push this module forward.

If you want to checkout the module, you can download it from the sandbox for now (http://drupal.org/sandbox/tomfriedhof/1412412). Once we get the namespace we’ve requested, we’ll promote it to a full project. Try the module out, file issues, and help out. Alan and I will be giving a BoF at SandCamp this Saturday, for those of you in town. Come join us, and hear about our motivations for building this module, and give us feedback.

Jan 17 2012
Jan 17

Posted Jan 17, 2012 // 2 comments

It's been about three months since I joined Phase2 as Community Manager, and I have really appreciated getting to know the needs of the community around Phase2's products and contributed modules. Thank you so much to those of you who have offered your honest -- and at times colorful! -- feedback. Truly, this is how we get better, move forward, and work together. In my last post, I talked about how we planned to respond to the community and about our goal to communicate more about our module contributions and product work. So I'm here to fulfill that promise. Here's what we've been working on:

1. Collaborative module maintenance: We have recently increased the number of module maintenance jams where our developers sit together and work on the modules we maintain. This helps our newer team members learn the modules, and gives our team the chance to bounce ideas around and come up with the best solutions. We are continuing to contribute code that the community will benefit from and, in turn, are reviewing code that the community has contributed back to our modules. (Thank you for those contributions, by the way!)

2. Straight up increase of module maintenance hours: The entire development team has been working on reviewing and committing patches and responding to issues in the issue queue. In the past month and a half, we have spent over 300 hours on module maintenance. We have released new versions of 11 modules and a new version of 3 of our products:

  • Akamai
  • Embeddables
  • Entity Boxes
  • Features
  • Open Atrium
  • OpenPublic
  • OpenPublish
  • OpenCalais
  • Rubik
  • Static 404
  • Strongarm
  • Test Content Flag
  • Video Embed Field
  • Views Boxes

In the past month, the team has also worked on the following 15 modules:

  • Boxes
  • Context
  • Context Field
  • Context HTTP
  • Default Content
  • Feeds
  • Google Analytics Statistics
  • Node Connect
  • Persistent URL
  • Services
  • Static 404
  • Tao
  • Twitter Pull
  • Views Arguments Extra
  • WYSWIYG Tools Plus
  • We are always looking for code and documentation contributions from our community. Code contributions are best submitted in the form of patches in the module issue queue. 

    3. Increasing Documentation: We've started with adding more documentation to the products themselves, and are continuing with more documentation around the modules. If you have suggestions for changes to the documentation on the module project page, please send me an email at [email protected]. For changes to additional module documentation, please click on the "Read Documentation" link under Resources on the right side of the module project project page. Anyone with a drupal.org account may edit this documentation.

    Check back as we continue to provide updates of our module maintenance progress in the upcoming months! We look forward to seeing your contributions!

As our Community Manager, Danielle is responsible for the communities around our products, which include OpenPublic, OpenPublish, Open Atrium, Managing News, and Tattler, as well as the Drupal modules we maintain.  She is also ...

Jan 05 2012
Jan 05

Posted Jan 5, 2012 // 11 comments

Overview

Happy Holidays!

In our last installment (A New Paradigm for Overriding Drupal Features) I presented a new sandbox module that allowed you to override Field Settings from existing Features. As promised, I have now generalized that approach and have created a new sandbox module called Features Override 2 that applies this method to any feature.

The Problem (revisited)

As a quick review, the problem we are trying to solve is dealing with site-specific changes to existing Features. The Drupal Features module allows you to capture configuration data, such as entities, fields, variables, views, permissions, etc into code modules.  These code modules can then be placed into version control, enabled and disabled, or used on a separate Drupal installation to provide the same feature.

In many cases, a Feature is developed for a generic site (or Distribution, such as OpenPublish) but needs to be slightly changed for the specific site you are developing. If you change the base distribution feature, it will be hard to upgrade to a newer version of that distribution feature. What you really want to do is just capture your changes to a site-specific "Override" feature and leave the original distribution untouched.

The New Solution

As we previously discussed, the existing Features Override module attempted to solve this problem but had many drawbacks. I have now taken the approach used to override Field Settings in the previous blog entry and applied that to all features types. As a new maintainer of the Features Override module, I intend this new sandbox to eventually become the 7-2.x release of Features Override.

Currently, the new Features Override 2 sandbox module requires a patch to the Features module: #1317054: Provide a universal hook for altering default components (although by the time you read this it may already be committed to the Features 1.x dev branch). The README.txt file included with the module documents the basic usage, but I'll review the highlights here.

Basic Usage

(Install and enable sandbox module. Apply patch to Features as needed)

Unlike the old Features Override module, overrides are handled just like any normal feature in the new sandbox. First install (or create) some "base" features for your site. For example, "base_article" containing the fields, content-type, or whatever you want. Next, make some changes to that component using the normal Drupal UI (for example, change the display settings of a field, or change the name of a view).

Once you have made changes, the Features page will show your base feature as being "overridden". To capture these changes into a new feature, just click Create Feature and select the new "Feature Override" exportable from the Components drop-down list. A list of overridden components will be shown. Check the box next to the ones you want to save, then Download Feature to create the feature. Install this new Override feature module on your site and enable it. Now the original feature will be shown in it's "Default" state, but the changes you made will be applied by the new Override feature.

Examining Overrides

Even if you never use this module to create any overrides it adds a very useful new tab for inspecting changes. In the past, the "Review Overrides" tab could be used to look at the "diff" between the live database and the stored feature code. But it couldn't really show the full context of the change. For example, if the change was to a display in a view, it was difficult to determine what view was being changed.

The new "Overrides" tab added by the sandbox module shows the line-level detail of the current changes.

Override_screen1

When you select a specific Override feature and click the new Overrides tab, a line-by-line list of the changes being overridden are displayed, along with a list of any new changes (not yet saved to a feature). Using the checkboxes you can completely control the line-level detail of which changes are saved to the Override feature and which are not.

Merging Features and Overrides

But wait, there's more! As detailed in the README file, you can also easily capture changes to an Override module, then apply those changes to another feature to "merge" the two features together. You can use this to make changes to the base feature without disturbing any override features. Or you can use this to update existing override features. The module provides a lot of flexibility for handling overridden features in a simple and intuitive way.

The Magic

The magic behind the scenes that allows feature overrides to finally work is a new hook that allows external modules to modify the code being generated by Features exportables. The Features Override 2 sandbox uses this new hook to alter the code being written, adding it's own "alter hook" to the exportable code. This alter hook is used to apply the changes from the override feature to the base feature. In the past, no such hook was available to modify the Features exportable code at this level. The old Features Override module tried to work around this limitation, but it just wasn't possible. Some features (such as Views) require careful handling of the changes so they are made to the correct part of the exported array structure. For example, changes to "current display" are ignored in favor of changes to the "displays[display-name]" array.

The core "diff engine" used in the Features Override module was maintained (slightly modified) to determine the set of additions and deletions needed for the override. But these changes are now selected "on the fly" in the Create Feature screen rather than needed to write them to an intermediate database table and module file. The new sandbox doesn't use any additional database tables or files.

As was the case in the previous blog article, the key was applying the alter hooks to the actual exportable code and then treating overrides as any other normal feature. It's a simple concept that gets a bit tricky in the implementation. And the nested level of hooks and alters can be confusing the first time you look at it. But in the end the goal of providing easy-to-use overrides of existing features was met.

Conclusion

I encourage you to grab the sandbox module and Features patch and start playing with this. Post any problems in the sandbox issue queue. Once a few other people have tested this and we get any major issues resolved, then I'll go ahead and rename this to Features Override and post it as the 7-2.x release.

Thanks to the Drupal community members: nedjo, tim.plunkett, hefox, febbraro, e2thex, and jec006 for their help and support with this work.

Attachments

Override_screen1-1.jpg

Mike Potter is a Senior Developer at Phase2 who loves to pair a solid technical solution with an intuitive client-focused design. Mike started his career as an experimental neutrino particle physicist before creating the first WWW home page ...

Dec 08 2011
Dec 08

This post describes generally how to create ajax paging comments, how to package the created comments into a feature, and how to override default views created by modules.

Ajax Comment Pagination

You know the biggest problem with comments? That's right, getting them to page using ajax so that users watching videos don't have to reload the page. Good answer!

So how does one go about making this happen in Drupal 6? Very easily actually. One simply makes their comments load in a view, and uses Views built in ajax to handle the pagination.

In Drupal 6, using the module CommentBlock will handle all the heavy lifting for you by providing a view for comments as a block, and preventing the output of comments on node pages.

So to start, download and install that module, then place the Comments and Comment Form blocks it provides in the content region of your site.

Next, visit the views page and edit the Comments view with the following settings:

  • Use Ajax: Yes
  • Use Pager: Yes
  • Items to display: 50 (or however many you want)

Save the view and voila! you now have comments that page using ajax.

Wow! you say? That's so awesome I want to use it on all my sites!, you say? No problem.

Enter Features

If you're interested in reusing site aspects you create on other sites, you must learn the Features module. It can package different components of your site into a downloadable and easily deploy-able psuedo-module for you.

Additionally, grab the Strongarm module. It lets you save drupal variables into features, and in this specific case is necessary.

After installing those modules visit your feature's page (Site Building » Features) and create a new feature. Name the feature, describe it and give it a version number, then add the following components.

  • Dependencies: CommentBlock, Views
  • Strongarm: clean_url

The reason we added the clean_url variable is because features that only have dependencies don't show up correctly on the features page.

Click Download, and save the feature you created.

Overriding default views in a Feature using hook_views_default_views_alter()

This is where it gets a little tricky. Since the commentblock module provides the Comments view as a default view within the module, we can't export the modified view into a feature, we're going to have to override that default view with code. Lucky us, one great thing about features is that you can add real module code into them!

First, go back to the comments view you edited earlier and click on 'Export'. Just keep that page open.

In your freshly created and downloaded feature, open the module file in your favorite editor, and add the following at the bottom of the file.

<?php /* * Implementation of hook_views_default_views_alter() * * Override the view provided by commentblock module * http://drupal.org/node/1014774 */ function FEATURENAME_views_default_views_alter(&$views){ // Alter only the 'comments' view. if (array_key_exists('comments', $views)) { /* * How To: * * 1) Install the commentblock module and edit the view provided as desired (comments) * 2) Export the edited view and paste the code below * 3) Cache flushing likely needed */ // paste exported view here. /* * Stop. Do not remove or change */ // Override the existing view with this new definition. $views['comments'] = $view; } }

Now simply go back to the page where you have exported the edited Comments view and copy all of the code provided in the textarea.
Then paste that code in the feature function above where it says 'paste exported view here.

Note: You'll need to replace the FEATURENAME in the function above with the folder name of your feature.

Save that file, and there you have it. Now to have ajax comment pagination on any other drupal 6 websites you need only to have the modules commentblock, views, features, and strongarm, along with your newly created feature.

I know that's a lot of steps crammed into a small blog post, but if you don't need to reuse the feature on other sites you only need to follow the first section.

Happy hunting!

Dec 02 2011
Dec 02

Using Features' component alter hooks to export components with dynamic elements

Posted on: Friday, December 2nd 2011 by Sheila Mullins

Note: These comments are based on Drupal 6, although the hooks are also available in Drupal 7.

The Features module is a great development tool that allows you to grab components stored in the database of your local development environment and export them to code so they can be transferred to other environments. Using Features to export content types, cck fields, views, feeds importers, imagecache presets, and many other components and settings has made development and deployment a lot smoother. Even better was learning about the hooks that allow you to alter the default components exported by features. Here are a couple of situations where these hooks provide just the fix needed.

Problem: Hard-coded vids, tids and rids in exported views

An exported view can contain hard-coded vocabulary vids, term tids or role rids which may not correspond to the same vocabularies, terms or roles in a different environment. If you change the code in the hook_views_default_views() function implemented by features, the code will be overwritten anytime you update the feature and you would have to make those same changes over again each time.

Don't make any changes to the hook_views_default_views() function in the file created by features. Instead add a hook_views_default_views_alter() function in the .module file and make your changes there. (While other alter hooks are provided by the features module, the views module provides this one.) If you store your id in the variables table when you create your vocabulary, term or role, then you can retrieve it from the variables table and in any environment it will refer to the correct vocabulary, term or role.

define('MYMODULE_MYVOCAB_VID', variable_get('my vocab vid', null));

/**
 * Implementation of hook_views_default_views_alter().
 */
function mymodule_views_default_views_alter(&$views) {
  if (isset($views['view_name'])) {
    $views['view_name']->display['block_1']->display_options['filters']['vid']['value'] = array(MYMODULE_MYVOCAB_VID => MYMODULE_MYVOCAB_VID);
  }
}

Problem: Hard-coded arguments for quicktab views

I was exporting a quicktabs block containing views and I wanted to pass an argument to each view based on the current date. Features exports quicktabs blocks using hook_quicktabs_default_quicktabs() but any arguments for included views are hard-coded.

Solution: hook_quicktabs_alter() (patch required)

You'll have to apply the patch filed against this issue before implementing this hook. Once again, place this hook in the .module file of your feature module and you can access any of the quicktab settings you would like to change.

/**
 * Implementation of hook_quicktabs_alter().
 */
function mymodule_quicktabs_alter(&$quicktab, $op) {
	if ($quicktab->machine_name == 'my_block' && $op == 'view') {
    // Some code to set default tab ($default_tab_key)
    // and an array of arguments for each tab ($date_args)
    
    // Set default tab and date args for all tabs.
    $quicktab->default_tab = $default_tab_key;
    foreach ($quicktab->tabs as $key => $quicktab) {
      $quicktab->tabs[$key]['args'] = $date_args[$quicktab['title']];
    }
  }
}

Problem: CCK content taxonomy field with hard-coded vid

One last example, same idea. The content taxonomy field exported by views uses a hard-coded vid but I want to set the vocabulary dynamically.

Use this hook to alter any of the settings exported by features in hook_content_default_fields() in the mymodule.features.content.inc file.

/**
 * Implementation of hook_content_default_fields_alter().
 */
function mymodule_content_default_fields_alter(&$fields) {
  if (array_key_exists('my_node_type-field_my_cck_field', $fields)) {
    $vid = //code to get vid...
    $fields['my_node_type-field_my_cck_field']['vid'] = $vid;
  }
}

Sep 02 2011
rmo
Sep 02

Project deployment using Features

Posted on: Friday, September 2nd 2011 by Richard Mo

The contributed module, Features, has been out in the community for a while, and has been a tremendous help for deployment. It saves time and energy when moving from Development, Staging, then Production. Configurations become a 'one-click' solution, so to speak.

However, careful planning needs to be incorporated when creating packages with Features. Sometimes two Features can be in conflict with each other when both packages are using the same element - this is especially true for CCK fields. Features doesn't offer the easiest way to move elements within a package to another. For example, if Package A stores a content-type that has CCK fields and Imagecache presets, then to move it, any dependencies must be released manually. Here are a few tips, that I use, to ensure a smoother process for development and deployment:

  1. Whenever possible, group all related content-types, views, pages, etc. into a single package. Better yet, modulate functionalities or features into an atomic unit, so it is isolated and encapsulated.
  2. Try to minimize the amount of sharing of existing CCK fields among other content-types. Content-types within the same atomic grouping can share the CCK fields.
  3. Plan ahead the exact architecture of the site. Most important step!

Jul 04 2011
Jul 04

For developers who are new to Drupal, I think that one of the modules that you should learn how to use and maximize is Features. Features is essentially a platform in which allows site/contributed settings to be exportable/importable. It comes in handy when propagating database changes across servers or local machines (imagine if you are in a group, working on a project).

read more

Jun 30 2011
Jun 30

Too busy doing the doing to talk about the doing?

As a strategy and design studio, we're all over communications. It's an uninterrupted conversation with our clients, hashing out ideas, working iterations of goals definition, research, wireframes, designs. But when it comes to development, when we put our heads down and get to work, it's all too easy for us in our focused implementation state to just do it and not communicate enough about what we're doing. Of course, this can be disconcerting to the client who has no idea how things are going. And that's a ripe situation for fear, uncertainty and doubt to creep into the relationship, and suddenly a successful project-in-progress can feel troubled, even if it's not.

The simple solution is to give regular status updates, which is something we've always done. Even just saying, "Things are going well" can help. But on long projects, or even in 3-week iterations, repeating that same message ends up being not that helpful. Better to share what you're thinking with regards to planning and project management, and provide updates on development of the various features/backlog items worked out in the strategy and design phases. This transparency in the project management process is even better when updates are more specific.

We have been using Open Atrium, the powerful intranet CMS built in Drupal, developed initially by our friends at Development Seed, now maintained by Phase2 Technology, for our intranet to handle all client-facing communications, documentation, file sharing and issue tracking. It's been a great tool for this. No missed emails lost in the spam filter. No critical documentation lost on someone's hard drive. No mega-emails containing two dozen specific items. (Well, those still happen on occasion, but we now can push those into the intranet to continue discussion.) We love it.

And now we love it even more.

Rethinking Open Atrium

We had been using almost all of Open Atrium's various features: messages, uploads, case tracker, books for documentation, and of course the groups functionality. Almost all of the features. The part that didn't really fit in with our communications strategy was the OA notion of "Projects". Until now.

You see, in Open Atrium, the basic architecture is thus: You have Clients, which are defined by groups, and you have Projects, which are ways of grouping tickets within the group by project. It can make sense for a large organization using OA for internal communications to manage several projects. But for a professional services firm like a strategy and design company, or a software company, or any other kind of company that defines work by time-boxed iterations or sprints, breaking up stuff by "project" may not be that useful. Projects projects projects blah! At PINGV, we rarely have a series of small projects with a client where it would make sense keeping them all together in one group; we tend to do bigger projects, projects that have phases of strategy, design and planning, and iterations of development. And when we have a new large-ish project with an existing client, we just spin up a new Atrium group. Project was that dunsel feature — the thing that for us had no real use. But—

What if we use "Project" nodes to define phases and iterations?

Wash that nomenclature right out of OA

Ignoring nomenclature, and just looking at what "Project" as a functionality in Open Atrium does for us, it provides a way to group tickets into clumps that you can define by anything. If we define those clumps as iterations, perhaps, or phases, we can organize and parse through backlog items, features, questions and other tickets by iteration, while providing some ready clarity as to how and when these items will be taken on. (NB: It's an approach that works only with Tickets, not other node types, but in our mind that's a minor limitation.)

What's really convenient is that Open Atrium provides via UI the means to rename "Project" to whatever you prefer to call it (e.g., "Iteration"). These string replacements, configured in the group feature settings available to site administrators from within each group's space, work almost everywhere in OA. (The "Add Project" button seems to be unaffected even by string replacements defined in settings.php. Something to investigate later.)

Once we saw this potential for grouping issues into iterations, we ran with it.

Defining iterations in Open Atrium

Open Atrium screenshotUsing "projects" in Atrium, we can define iterations by close date, and assign tickets to iterations.

As you can see, the Iteration title is compressed down to an abbreviation or acronym in the icon in the tickets display. "Iteration 1" becomes "I1", "General" becomes "GENERA", and so on. After briefly considering using iteration numbers, which we rejected as too arbitrary, we opted to name iterations by the Iteration release date, or end date (e.g., 08/17 or even 11/10/23), which can be abbreviated in a meaningful way in the Tickets views. This gives our clients added insight into our timetable planning at a glance.

Adding a sortable Iteration column to the tickets view involves a simple override to the default ticket View. (If ever we need to revert that Feature during a site update, these changes are easily re-implemented in a few minutes. No actual data is affected.)

Open Atrium screenshotYou can view all of the iterations planned, and see their descriptions. Each iteration is clickable for detailed viewing.

This approach allows us also to focus just on the tickets that are relevant now, without having to sort through all the other tickets that are further down in the timetable, and without having to mark dozens (hundreds?) of individual tickets as "deferred" and then change those as they come available.

Open Atrium screenshotSingle iterations of backlog items can be viewed as well, and this is stock functionality for Open Atrium.

The bulk of communications still happens in the individual tickets. Questions, information, updates, concerns, notes can be tied to the ticket itself. New questions and bug reports can also be slotted for attention in a scheduled Iteration. So even though we're grouping our backlog items together, we still avoid the one-ticket-for-8-issues kind of communications that can lead to confusion, frustration and missed messages.

Open Atrium screenot
On any comment update, you can change the iteration assignment of a ticket.

comment status change
All changes are tracked in the comment metadata displayed right there in the thread.

We like this system so far because of this fact that all changes are tracked and visible in each ticket's thread. If we move up a backlog item to a higher priority, we simply do it with a comment and change in iteration designation. This flexibility with traceability provides a nice balance for communicating our planning.

And it's all using stock Open Atrium!

Plan before communicating, and vice versa

I should add that this is not how we do our actual project management. Open Atrium is a great tool for project-related communications. We currently use Brian's recommendation, we tried Liquid Planner (disclosure: affiliate link; go to liquid planner dot com to skip it if you like) for our internal planning. Liquid Planner has an API, and we're considering developing an integration with Open Atrium to allow us to push and pull info between the two. Might be a nice convenience. We do the translation manually now, and while it can take up time on occasion, it also provides an occasion to rethink and re-evaluate, so the manual process does have value.

Feature think, Feature do

Now for the road not taken:

When first considering the challenge of better communicating our iterations plans, I imagined up a very simple Features-based solution using nodes and node reference, which resulted in Open Atrium Iterations. This module works as a drop-in extension to Open Atrium. Not touching any existing Atrium Features, OA Iterations defines a new content type with reference fields to call up tickets (cases), messages (blog posts) and documentation (books) that collectively define and describe an iteration of work. A dedicated view restricts the available referenced nodes to the current group's content.

On Friday afternoon, this seemed like a fine way to communicate our iteration planning. Tickets, as well as blog posts and book nodes, could live on their own, with their own revisions and threads, while the Iteration node would group them into an iteration. Done. Time to relax and prepare for a weekend cleaning the garage.

On Monday morning, however, when I sat down to start defining the iterations for one of our projects, I immediately questioned my own game plan. Open Atrium Iterations was an easy way to define iterations, but making changes would be difficult. What if I wanted to move a ticket from one iteration to another? Yes, this project was never intended for iteration planning, just iteration communication, but even just for communications this approach would mean editing at least two Iteration nodes just to "move" one backlog item. What's more, without implementing Reverse Node Reference and adding that block to one or more Contexts (and thus overriding stock Open Atrium Features), there was no way to look at a backlog item and see what iteration it's slotted for. The simple solution was not turning out to be so simple after all.

And that's when the flicker of the idea described above came to mind. In hindsight, I can smack myself for not thinking of this before. I've been working with Atrium for two years. But I think I got stuck on nomenclature.

Contrib status

Meanwhile, despite our not using it as originally planned, Open Atrium Iterations will remain live on Drupal.org to see if it proves helpful to others. If the Feature can be improved upon to make it more broadly useful to serve more use cases, I look forward to suggestions in the issue queue.

Feb 10 2011
Feb 10

on 10 February, 2011

Here are the slides from the short talk I did on Development Seed's excellent Features module, at the February Drupal-Drop In, hosted at Microsoft's offices in London.

It was a great evening, where several people did a short talk on their favourite modules, or modules that they find themselves using all the time. Thanks to everyone who came along! For those who missed it, there's a good re-cap over at UBelly.

Dec 27 2010
Dec 27

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.

Features

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.

Security

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.

git

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

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.

Modules

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:

  • 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.

  • 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.

  • 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.

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

  • 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.

  • 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.

  • 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".

  • 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

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.

Workflow

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.

Sep 28 2010
Sep 28

A few weeks back, we wrote about our thought process for building features, and how we wanted to make sure that the features achieved two goals:

  • Be part of a fully functioning install profile that "just worked"
  • Be as reusable as possible within VoiceBox variants, or within other sites.

As part of achieving these goals, we created an option within our install profile that allows a user to select the Full or the Minimal install. The full install runs through the complete install, and creates a fully functioning site.

Minimal or Full install option

The minimal install, however, runs through the install profile, and then allows the site builder to enable the selected features they want.

Features are modules; this allows us to set dependencies between features. However, as we built out features based on our site configuration, we realized that the User Interface elements created the largest set of dependencies - and this makes sense, because a good UI collects up the various sets of functionality and presents them to users in an intuitive, coherent way. To account for this, we split out our UI into separate features, so someone doing a minimal install can choose to use these defaults, or build their own UI.

A graph of the dependencies shows this better than words can explain it:

  • Dependency tree of VoiceBox without any UI (click the image to see a full-size version):

    Feature dependencies with no UI

  • Dependency tree of VoiceBox with the UI features included (click the image to see a full-size version):

    Features dependencies, including the UI

    The elements pictured in blue are the UI-related features; within the site, they expose functionality to end users - this is also known as "making things useful or usable."

    Within the features, UI elements create a higher level of interdependence.

We are running through the last few rounds of testing here, and barring any nasty last-minute surprises, we should have a release of VoiceBox by tomorrow. Our features server, which will be launched with the site, will allow people to get the entire install as a package, or the bundled features individually.

Aug 29 2010
Aug 29

DrupalCon Copenhagen comes to an end, as does my blogging hiatus.

Two of my primary learning objectives here in Copenhagen were configuration management and deployment process. Historically, working with Drupal in these areas has been unpleasant, and I think that's why there is tons of innovation going on in that space right now. It needs to be fixed, and new companies are springing up to say "hey, we fixed it." Often, the people running the companies are the same people running the project that encapsulates the underlying technologies. I'm referring to:

  • The hyper-performant core distro, Pressflow
  • Distros with sophisticated install profiles, like OpenAtrium, ManagingNews and OpenPublish
  • Configuration externalization with Features
  • Development Seed's "for every site, a makefile" workflow using drush make
  • The different-yet-overlapping hosting platforms Pantheon and Aegir

Dries commented in his keynote that as Drupal continues to grow, it also needs to grow up. I think advances like these are part of the community's answer to that. I want to wrap my head around some of these tools, while continuing to watch how they progress. Others, I want to implement right now. What's perfectly clear though is that I have a lot of work to do to keep up with the innovation going on in this hugely powerful community. Which is actually nothing new, but reading a blog post about these technologies doesn't make my jaw drop the way that it does when I'm in the room watching Drupal advance.

Pages

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