“Excuse me, Mr./Mrs. Client, I’m so sorry but I accidentally just sent your 3000 users a fake purchase email receipt when I was testing.”

Ugh.

Big complex systems are a lot to keep track of, especially when it comes to email. There are emails for resetting passwords, emails for new users, email receipts, email notifications for workflows, etc, and it’s frankly a little terrifying to rely on yourself to remember all the implications of what’s going on when working on local environments, or test servers or anywhere but production. All you have to do to experience this pain is trigger an accidental FAKE email send to REAL people.

That’s where modules like today’s spotlight comes in.

We’re talking about the Reroute Email module, a simple plugin that allows you to override all outbound email sending and send them to a configured address, allowing you to both test that email content is working but not have to apologize to all of your users.

Installation is simply turning the module on and then going to the configuration page at /admin/config/development/reroute_email. From there, you can set the rerouting email addresses and even set whitelisting emails that are permitted to pass through the reroute.

This is helpful for situations where you want to use test emails for specific purposes and you want the emails to go out as they will in production without having all email functionality enabled on your site. Pretty great. Lastly, you can even enter module key patterns so that emails coming from particular modules are the only ones being rerouted. Very flexible.

And a special note: On many of our sites, we set the config for the module in the local settings files for each environment so we can ensure, for example, that local or test environments never send real emails even if we pull code or refresh the database from production. It’s as simple as the following lines of code:

The holidays are over for a while now, so it’s about time for a new blog. In this article I’ll discuss 12 modules that can help you get started with a great Drupal site:

1. Max image size

A default Drupal installation can check if an uploaded image is too large and display a warning. This module does something similar but is also checking previously uploaded images that are too large and likely taking up too much space. It scans all the images (also already uploaded ones) and reduces the size of the original

2. User Import

3. Select (or other)

Drupal’s form API knows by default a select element that allows you to offer choices to those who enter content. This element is limited to the provision of predefined terms (categories). After installing this module, this element can be expanded with an additional field: let the end user choose ‘other’ and offer a free selection field.

4. Captcha-free Form Protection

Everybody wants to be protected against spammers, this is often done through the Captcha technology; probably you have heard of this before. This module protects you against spammers without Captcha, since this is often a barrier for visitors.

The module applies other techniques (‘behind the scenes’) such as checks if cookies / javascript are disabled, it can also check whether a certain time has exceeded. On the basis of these data it can determine whether the person who sent a form is most likely a spammer or not. The Honeypot module contains similar end features.

5. Twitter block

6. Leaflet

Leaflet is a javascript library that is quickly becoming popular and that let’s you create maps. It is an alternative to Google maps, allowing you to easily create customized maps and integrate external map services (for example Mapbox, Stamen or Thunderforest). Easy to configure, mobile-friendly to navigate and light in code.

7. Better watchdog UI

The Drupal core has a logging module which gives great insights in errors, notices, content and user actions, etc. Install this module if you want to filter better in this log. FYI: Till Drupal 5 Drupal’s logging module was called ‘watchdog’, this term is still used for logging elements.

8. Check for acknowledgement

In some cases you want to know whether users of your system have read a particular piece of content. This is now possible after installing this module: it places a check mark at the bottom of a content page. Users placing the check mark are logged which is visible to you as a site administrator. This allows you to see who really confirmed they read the article.

11. Date Facets

12. Read only mode

When putting your system in the maintenance mode in a default Drupal installation, the entire system will be temporarily put offline; the visitors will receive a maintenance message. Usually you would prefer that nobody is logged in on your site, as content can be changed during the update process. Those changes could be lost.

If you can ensure that nobody can enter/change content during maintenance, then you are also adequately covered — provided that your update is not generating errors. This module is doing just that: it places your site in the maintenance mode, so visitors can still view the site but cannot enter/change content.

So…. Drupal 8 got released! Congrats everybody! The end of life of Drupal 6 is then final. In addition, the 16th of november it was announced that Drupal.org is now serving its content and files via Fastly; which is giving a significant performance boost, well done!

Furthermore, what I noticed last month on module updates:

1) Scroll to destination anchors

This module modifies the behaviour of an ‘anchor’ within a page. So the page will not jump down but fluently scroll down. We have installed this module here.

2) Spider Slap

There are a lot of ‘evil spiders’ active on the internet. These are web crawlers that don’t respect what is written in your robots.txt. This can cause unnecessary load on your server and uncover information that you don’t want to see in a search engine. This module is solving this problem. It will block the IP when a spider does not behave, with as a result that it will no longer have access.

4) Database Email Encryption

Do you want to maximise the security of the email addresses of your registered users? This is possible with this module. It encrypts the addresses in the database. Should the database end up in the wrong hands, then the email addresses cannot be read. Encryption is done using AES.

5) Unique field

A popular module existing since Drupal 5, but I never noticed it before. It is performing a check on entered fields (e.g. title field) and checks whether the entered title is unique. This will prevent the use of double titles which is good for, among others, SEO.

6) Login History

By default Drupal is not creating a login archive. This module will do this for you: it creates an archive in which the history of logins will be stored.

9) Client side Validation

10) App Link

Probably you recognize this one: the message above a website on your Smartphone that you can view the page in a native app. If you built and linked an app (e.g. via DrupalGap) then you can generate this ‘app message’ on your Drupal website using this module.

12) Simple XML sitemap

The title of this Drupal 8 module says it all: it provides an XML sitemap that you can upload to search engines, so you can see the indexation of all your site links in the relevant search engine. The module also has a few configuration options like setting ‘priority’.

13) Session Limit

Tighten the security of your Drupal system by limiting the number of sessions with which a user is logged in. You can for example set that somebody can be logged in once; if somebody is logging in on his/her Smartphone then he/she will be automatically logged out on the work computer.

15) OpenLucius LDAP

Another own module, that should be mentioned as well ;-). This module extends Drupal social intranet OpenLucius with a LDAP connection, so that users can login to OpenLucius with their existing LDAP account.

Google Summer of Code (GSoC) is into the next phase of coding after the mid-Term evaluations which got over by June 27th. This also reminds students to speed up the coding activities to complete the projects within the schedules provided in the proposal.

I am porting Search Configuration module to Drupal 8 as part of this year’s summer of code. GSoC is definitely turning out to be a venue for the young students from universities around the world to work on real-world projects under the experience of well-known developers, learning new technologies, making use of version control systems, with regular meetings and finally building up a software which is going to help a large section of the society.

I blog regularly, sharing my project progress. If you would like to have a glimpse of my past activities on this port, please visit this link.

Drupal 8 has introduced the concept of Html twigs in place of the PHP templates. So, the PHP template files have to be now ported to the Html environment. The .tpl.php template file is replaced by the .html.twig file for the module templates. Templates are simply text files which can give outputs in Html, Latex, CSV or XML formats.

To print some data, we usually take the service of echo statements in PHP. The print statements are replaced by {{ }} in Html twigs.

<?php echo t(‘Let’s start the process.’); ?>

is replaced by:

{{ ‘Le’s start the process’|t }}

The variable names have to be converted to simple names. For instance,

$page[‘title’]

becomes

{{ title }}

The PHP logics have to be replaced by {% %} syntax. This is applicable to all the logical statements.

<?phpif ($page[‘title‘]):?>

…..

<?phpendif;?>

is transformed as:

{% ifform %}

……

{% endif %}

Also, the variables are replaced by simple names.

<?php if ($logo): ?>

is transformed as:

{% if logo %}

These were some of the basic transformations to get started into created the HTML twigs.The use of the Html twigs has made the templates look very simple and easily understandable. It is really easy to get the templates converted to the Html twigs. This is always one of the crucial requirements of porting modules from Drupal 7 to Drupal 8.

Google Summer of Code (GSoC), has entered into the mid-Term evaluation stage. This is a 1 week period from 21- 27 June, were students and mentors present the progress of their projects. Based on the reports submitted, students are made pass/ fail.

I have been working on porting Search Configuration to Drupal 8 in the past few weeks. If you would like to have a quick glimpse of my past activities on this port process, please go through these posts.

last week, I could learn some Drupal concepts which were really helpful for my project. In the previous versions of Drupal, the role permissions were stored in a role_permissions table in the Database. But now, in Drupal 8, the role permissions are directly stored in the role configuration entity.

So, as described above, in D7 and its preceding versions, role permissions were stored in a role_permissions database which had the role Id and the corresponding permissions. The permissions distributed to a role was retrieved in D7 using:

$permissions = role->getPermissions();

But, in D8, this is done by the

$permissions = role->getPermissions();

Another instance is that, to grant certain permissions to roles.

In D7 it was controlled by,

user_role_grant_permissions($rid, array(‘ access content’));

The role configuration entity remodels this functionality in D8 to:

$role->grantPermission(‘ access content’);

In connection with the term permissions, the most important aspect in Drupal is a hook: hook_permissions(). This hook, obviously as you might have guessed, distributes the permissions to various users; decides whether a particular user should be allowed to access a page or a content, granting and restricting the access.

This hook has been replaced in Drupal 8 by a module.permissions.yml file. This file contains the permissions and its specifications. We can write a driver function in a php file to add the dynamic permissions. This can be achieved by making a driver class in the php file and adding the behaviour of the permission we need in the member functions of the class. We also have to link this PHP file with our yml file to keep it active. This is done by adding a callback function in the yml file which references this php file.

To display special characters in a plain text string for display as HTML format, Drupal earlier versions used the function check_plain. This had the general syntax:

check_plain($text); // where $text was the string to be processed.

This function has got deprecated in Drupal 8. This has been replaced by the \Drupal\Compoent\Utility\Html::escape($text).

I have been selected for the Google summer of Code’ 16 for Drupal for the project, Port search configuration module to Drupal 8. Thanks to all the developers in #Drupal IRC channel for guiding me into this summer project by sharing their ideas and suggestions.

The search configuration feature is presently available in Drupal 7 and its preceding versions. This is really a cool feature which helps us a lot in improving the search and enhancing it for better search results. This summer, I will be engaged in porting this module to Drupal 8.

The GSoC projects were announced on April 22, 2016. All selected students have a community bonding period till May 22nd. This is the time when students get closer to the organisation, learn the organisation code base, interact with mentors, plan more about the project and its deadline for the coding period which starts soon after this community bonding.

I have been blessed with three experienced mentors from Drupal- Naveen Valecha, Neetu Morwani and Karthik Kumar. I have been discussing with them regarding the project plan for the last few weeks. Meanwhile, I was also asked to learn some of the basic concepts of Drupal like hooks, hook permissions, forms in Drupal which are the real components of my project. This helped me a lot to understand more about the coding methodologies I need to adopt. I could go through the code base of the module in Drupal 7 which has helped me collect more ideas for the project.

I also got the opportunity to hack with some simple modules by creating a sandbox project in Drupal and pushing commits on sample module developments I did to learn the basics of the module. I have created a project in Drupal for the search configuration port and has added the tasks I need to complete in association with this process.

We just launched our first Drupal 8 website for the Northwest Atlantic Marine Alliance (NAMA). During our project retrospective, a few of us brought up how nice it was that so many contrib modules that were part of the D6 site weren’t necessary in Drupal 8 – this was a major factor in making it possible to launch this project before the actual D8 release.

The graphic below compares contrib modules that were running on NAMA’s Drupal 6 site compared to the modules needed to achieve the same functionality in Drupal 8.

Having so many of the modules that we always install built into core gave us more time to focus on ways to optimize the site for NAMA’s specific needs, and it should also save us time down the road when it’s time to handle maintenance tasks (like security updates) or add on new features.

What are you most excited about having in core?

Which modules are you waiting to see in D8 before upgrading?

This is the third in a series of blog posts about the relationship between Drupal and Backdrop CMS, a recently-released fork of Drupal. The goal of the series is to explain how a module (or theme) developer can take a Drupal project they currently maintain and support it for Backdrop as well, while keeping duplicate work to a minimum.

In part 1, I introduced the series and showed how for some modules, the exact same code can be used with both Drupal and Backdrop.

In part 2, I showed what to do when you want to port a Drupal module to a separate Backdrop version and get it up and running on GitHub.

In part 3 (this post), I'll wrap up the series by explaining how to link the Backdrop module to the Drupal.org version and maintain them simultaneously.

Linking the Backdrop Module to the Drupal.org Version and Maintaining Them Simultaneously

In part 2 I took a small Drupal module that I maintain (User Cancel Password Confirm) and ported it to Backdrop. In the end, I wound up with two codebases for the same module, one on Drupal.org for Drupal 7, and one on GitHub for Backdrop.

However, the two codebases are extremely similar. When I fix a bug or add a feature to the Drupal 7 version, it's very likely that I'll want to make the exact same change (or at least an extremely similar one) to the Backdrop version. Wouldn't it be nice if there were a way to pull in changes automatically without having to do everything twice manually?

If you're a fairly experienced Git user, you might already know that the answer is "yes". But if you're not, the process isn't necessarily straightforward, so I'm going to document it step by step here.

Overall, what we're doing is simply taking advantage of the fact that when we imported the Drupal.org repository into GitHub in part 2, we pulled in the entire history of the repository, including all of the Drupal commits. Because our Backdrop repository knows about these existing commits, it can also figure out what's different and pull in the new ones when we ask it to.

In what follows, I'm assuming a workflow where changes are made to the Drupal.org version of the module and pulled into Backdrop later. However, it should be relatively straightforward to reverse these instructions to do it the other way around (or even possible, but perhaps less straightforward, to have a setup where you can do it in either direction).

To start off, we need to make our local clone of the Backdrop repository know about the Drupal.org repository. (A local clone is obtained simply by getting the "clone URL" from the GitHub project page and copying it locally, for example with the command shown below.)

The URL I used here is the same one I used in part 2 to import the repository to GitHub (that is, it's the public-facing Git URL of my project on Drupal.org, available from the "Version control" tab of the drupal.org project page, after unchecking the "Maintainer" checkbox - if it’s present - so that the public URL is displayed). I've also chosen to give this repository the name "drupal". (Usually the convention is to use "upstream" for something like this, but in GitHub-land "upstream" is often used in a slightly different context involving development forks of one GitHub repository to another. So for clarity, I'm using "drupal" here. You can use anything you want to.)

Next let's pull in everything from the remote Drupal repository to our local machine:

You can see it has all the branches and tags that were discussed in part 2 of this series. However, although I pulled the changes in, they are completely separate from my Backdrop code (the Backdrop code lives in "origin" and the Drupal code lives in "drupal").

If you want to see a record of all changes that were made to port the module to Backdrop at this point, you could run git diff drupal/7.x-1.x..origin/1.x-1.x to examine them.

I made the code changes on my local checkout of the Drupal version of the module (which I keep in a separate location on my local machine, specifically inside the sites/all/modules directory of a copy of Drupal so I can test any changes there), then committed and pushed them to Drupal.org as normal.

Back in my Backdrop environment, I can pull those changes in to the "drupal" remote and examine them using git log:

Sure enough, this is telling me that there is one commit on the Drupal 7.x-1.x version of the module that is not yet on the Backdrop 1.x-1.x version.

Now it's time to merge those changes to Backdrop. We could just merge the changes directly and push them to GitHub and be completely done, but I'll follow best practice here and do it on a dedicated branch with a pull request. (In reality, I might be doing this for a more complicated change than a simple documentation fix, or perhaps with a series of Drupal changes all at once rather than a single one. So I might want to formally review the Drupal changes before accepting them into Backdrop.)

By convention I'm going to use a branch name ("drupal-2415223") based on the Drupal.org issue number:

In this case, the merge was simple and worked cleanly. Of course, there might be merge conflicts here or other changes that need to be made. You can do those at this time, and then git push to push the changes up to GitHub.

Once the changes are pushed, I went ahead and created a pull request via the GitHub user interface, with a link to the Drupal.org issue for future reference (I could have created a corresponding issue in the project's GitHub issue tracker also, but didn't bother):

Using the above technique, it's possible to have one main issue (in this case on Drupal.org) for any change you want to make to the module, do essentially all the work there, and then easily and quickly merge that change into the Backdrop version without the hassle of repeating lots of manual, error-prone steps.

Hopefully this technique will be useful to developers who want to contribute their work to Backdrop while also continuing their contributions to Drupal, and will help the two communities continue to work together. Thanks for reading!

Further Backdrop Resources

Do you have any thoughts or questions, or experiences of your own trying to port a module to Backdrop? Leave them in the comments.

This is the second in a series of blog posts about the relationship between Drupal and Backdrop CMS, a recently-released fork of Drupal. The goal of the series is to explain how a module (or theme) developer can take a Drupal project they currently maintain and support it for Backdrop as well, while keeping duplicate work to a minimum.

In part 1, I introduced the series and showed how for some modules, the exact same code can be used with both Drupal and Backdrop.

In part 2 (this post), I'll explain what to do when you want to port a Drupal module to a separate Backdrop version and get it up and running on GitHub.

In part 3, I'll explain how to link the Backdrop module to the Drupal.org version and maintain them simultaneously.

Porting a Drupal Module to Backdrop and Getting it Up and Running on GitHub

For this post I’ll be looking at User Cancel Password Confirm, a very small Drupal 7 module I wrote for a client a couple years back to allow users who are canceling their accounts to confirm the cancellation by typing in their password rather than having to go to their email and click on a confirmation link there.

We learned in part 1 that adding a backdrop = 1.x line to a module’s .info file is the first (and sometimes only) step required to get it working with Backdrop. In this case, however, adding this line to the .info file was not enough. When I tried to use the module with Backdrop I got a fatal error about a failure to open the required includes/password.inc file. What's happening here is simply that Backdrop (borrowing a change that's also in Drupal 8) reorganized the core directory structure compared to Drupal 7 to put most core files in a directory called "core". When my module tries to load the includes/password.inc file, it needs to load it from core/includes/password.inc in Backdrop instead.

This is a simple enough change that I could just put a conditional statement into the Drupal code so that it loads the correct file in either case. However, over the long run this would get unwieldy. Furthermore, if I had chosen a more complicated module to port, one which used Drupal 7's variable or block systems (superseded by the configuration management and layout systems in Backdrop) it is likely I'd have more significant changes to make.

So, this seemed like a good opportunity to go through the official process for porting my module to Backdrop.

Backdrop contrib modules, like Backdrop core, are currently hosted on GitHub. Regardless of whether you're already familiar with GitHub from other projects, there are some steps you should follow that might not be familiar, to make sure your Backdrop module's repository is set up properly and ultimately to get it included on the official list of Backdrop contributed projects.

Importing to GitHub

The best way to get a Drupal module into GitHub is to import it; this preserves the pre-Backdrop commit history which becomes important later on.

Before you do this step, if you're planning to port a Drupal module that you don't maintain, it's considered best practice to notify the current maintainer and see if they'd like to participate or lead the Backdrop development themselves (see the "Communicating" section of the Drupal 7 to Backdrop conversion documentation for more information). In my case I'm already the module maintainer, so I went ahead and started the import:

Go to the GitHub import page and provide the public URL of the Drupal project's Git repository (which I got from going to the project page on Drupal.org, clicking the "Version control" tab, and then - assuming you are importing a module that you maintain - making sure to uncheck the "Maintainer" checkbox so that the public URL is displayed). Drupal.org gives me this example code:

As a final step, I edited the description of the GitHub project to match the description from the module's .info file ("Allows users to cancel their accounts with password confirmation rather than e-mail confirmation").

Cleaning Up Branches and Tags

Next up is some housekeeping. First, I cloned a copy of the new repository to my local machine and then used git branch -r to take a look around:

Like many Drupal 7 contrib projects, this has a 7.x-1.x branch where all the work is done and a master branch that isn't used. When I imported the repository to GitHub it inherited those branches. However, for Backdrop I want to do all work on a 1.x-1.x branch (where the first "1.x" refers to compatibility with Backdrop core 1.x).

We want to delete the master branch also, but can't do it right away since GitHub treats that as the default and doesn't let you delete the default branch.

So I went to the module's GitHub project page, where (as the repository owner) I have a "Settings" link in the right column; via that link it's possible to change the default branch to 1.x-1.x through the user interface.

On Drupal.org, this module has a 7.x-1.0-rc1 release, which was automatically imported to GitHub. This won't be useful to Backdrop users, so I followed the GitHub instructions for deleting it.

Finally, let's get our local working copy somewhat in sync with the changes on the server. The cleanest way to do this is probably just to re-clone the repository, but you could also run git remote set-head origin 1.x-1.x to make sure your local copy is working off the same default branch.

The end result is:

$ git branch -rorigin/1.x-1.xorigin/HEAD -> origin/1.x-1.x

Just what we wanted, a single 1.x-1.x branch which is the default (and which was copied from the 7.x-1.x branch on Drupal.org and therefore contains all its history).

Updating the Code for Backdrop

Now that the code is on GitHub, it's time to make it Backdrop-compatible.

To do this quickly, you can just make commits to your local 1.x-1.x branch and push them straight up to the server. In what follows, though, I'll follow best practices and create a dedicated branch for each change (so I can create a corresponding issue and pull request on GitHub). For example:

If you look at the diff, you can see that instead of simply adding the backdrop = 1.x line to the .info file, I replaced the core = 7.x line with it (since the latter is Drupal-specific and does not need to be in the Backdrop version).

With that change, the module works! Here it is in action on my Backdrop site:

(Also visible in this screenshot is a nice effect of Backdrop's layout system: Editing pages like this one, even though they are using the default front-end Bartik theme, have a more streamlined, focused layout than normal front-end pages of the site, without the masthead and other standard page elements.)

Other code changes for this small module weren't strictly necessary, but I made them anyway to have a fully-compatible Backdrop codebase:

I read through the instructions for applying to the Backdrop contributed project group. They're relatively simple, and I've already done almost everything I need above. The one thing I'm missing is that Backdrop requires a README.md file in the project root with some standard information in it (I like that they're enforcing this; it should help developers browsing the module list a lot), and it also requires a LICENSE.txt file. These were both easy to create following the provided templates and copying some information from the module's Drupal.org project page:

Once that's done, and after reading through the rest of the instructions and making sure I agreed with them, I proceeded to create an issue:

They are mostly straightforward. Just make sure to use "backdrop-contrib" as the name of the new owner (who you are transferring the repository to):

And make sure to check the box that gives push access to your repository to the "Authors" team within the Backdrop Contrib group (if you leave it as "Owners", you yourself wouldn't be able to push to it anymore):

For the same reason, you can keep your local checkout of the repository pointed to the old URL and it will still work just fine, although to avoid any confusion you might want to either do a fresh clone at this point, or run a command like the following to update the URL:

With the above steps, we’re all set; the module is on GitHub and can be developed further for Backdrop there.

But what happens later on when I make a change to the Drupal version of the module and want to make the same change to the Backdrop version (certainly a common occurrence)? Do I have to repeat the same changes manually in both places? Luckily the answer is no. In part 3 of this series, I’ll explain how to link the Backdrop module to the Drupal.org version and maintain them simultaneously. Stay tuned!

Further Backdrop Resources

Do you have any thoughts or questions, or experiences of your own trying to port a module to Backdrop? Leave them in the comments.

Part 1 - Reuse the Same Code

In mid-January, the first version of Backdrop CMS was released. Backdrop is a fork of Drupal that adds some highly-anticipated features and API improvements to the core Drupal platform while focusing on performance, usability, and developer experience.

When an open-source fork makes the news, it's often because it was born from a fierce, acrimonious battle (example: Joomla forking from Mambo); the resulting projects compete with each other on the exact same turf and developers are forced to choose sides. Backdrop's goal, however, is not to destroy or replace the original Drupal project. Rather, it aims to be a "friendly fork" that focuses on Drupal's traditional audience of site builders and developers, an audience which the Backdrop founders believe are being slowly left behind by the Drupal project itself.

Because of this, I expect that many existing Drupal developers will not want to choose between the platforms, but instead will continue working with Drupal while also beginning to use Backdrop. In this series of blog posts, I will explain how a module (or theme) developer can take a Drupal project they currently maintain and support it for Backdrop as well, while keeping duplicate work to a minimum.

In part 1 (this post), I'll show how for some modules, the exact same code can be used with both Drupal and Backdrop.

In part 2, I'll explain what to do when you want to port a Drupal module to a separate Backdrop version and get it up and running on GitHub.

In part 3, I'll explain how to link the Backdrop module to the Drupal.org version and maintain them simultaneously.

Sometimes the Same Exact Code can be Used With Both Drupal and Backdrop

To start things off let's look at Field Reference Delete, a Drupal 7 module I maintain which does some behind-the-scenes cleanup in your database when entities such as nodes or taxonomy terms are deleted on the site. It's a moderately-complex module which makes heavy use of Drupal's field and entity systems.

To make this or any Drupal module work with Backdrop, there is one step that is always required: Adding a backdrop = 1.x line to the .info file to inform Backdrop core that the code is Backdrop-compatible.

Easy enough. The big question is what changes are required beyond that?

Checking for Changes

Although Backdrop is not 100% compatible with Drupal 7 (due to the features and API improvements it adds) it aims to be backwards-compatible as much as possible, for example by including a compatibility layer to allow Drupal functionality that is deprecated in Backdrop to still work correctly.

The Backdrop change records and module conversion guide provide technical advice for developers on how and when to upgrade their code. The biggest changes are probably the configuration management system (Backdrop’s replacement for Drupal 7’s variable API and other configuration that was previously stored in the database) and layout system (which removes much of the functionality of the Drupal 7 Block module in favor of a newer, more powerful Layout module).

If your Drupal 7 module makes heavy use of these systems, it’s likely you’ll want to make some changes in order to work with Backdrop. However, the compatibility layer means that you might not actually need to. For example, Backdrop retains Drupal 7’s variable API (although it is marked as deprecated and is not as powerful as the configuration system which replaces it). So your code might still work even if it uses this system. It really depends on the details of how your module works, so the best advice is to test it out and see what (if anything) is broken.

It’s also worth noting that because Backdrop was forked from an early version of Drupal 8 (not from Drupal 7) it inherited a smattering of changes that were added to Drupal 8 early in the release cycle. Not all of these have made it into the list of Backdrop change records yet, although work is ongoing and people are adding them as they are noticed.

Adding the One Line of Code on Drupal.org

Interestingly enough, since Drupal will happily ignore a backdrop = 1.x line in a module's .info file, it's possible to simply add that code to the Drupal.org version of the module and use the same version of the module for either Drupal or Backdrop. I did that in this issue; the resulting diff is simply this:

Drupal uses the core = 7.x line to determine Drupal compatibility, and Backdrop uses the backdrop = 1.x line to determine Backdrop compatibility. The 7.x-1.0-beta1 release of Field Reference Delete contains the above change and can be used equally well on a Drupal or Backdrop site. Simple!

There are some downsides to doing this, however:

Although no changes to the module code may be strictly required, there are usually optional (and non-backwards-compatible) changes that can be made to better integrate with new Backdrop features.

It is hard for Backdrop users and developers to find the module and know that it's compatible with Backdrop. I tried to improve its discoverability by adding a "Backdrop compatibility" tag to the above-mentioned issue, and I also put a note on the project page explaining that Backdrop is supported. These aren't ideal, but should help; perhaps a standard will eventually catch on but there isn't a formal one yet.

Despite these disadvantages, for the time being I'd like to just have one copy of the code for this particular module (hosted in one place), and it's nice to know that's possible.

In part 2 of this series, I’ll take a look at a different module I maintain where it isn’t possible to use the same exact code for Drupal and Backdrop, and I’ll show how I went through the official process for porting my module to Backdrop and getting it hosted on GitHub. Stay tuned!

Further Backdrop Resources

Do you have any thoughts or questions, or experiences of your own trying to port a module to Backdrop? Leave them in the comments.

Drupal's content modeling toolbox makes it easy to add simple values to any content type -- numbers, text fields, dates, and so on -- but odd gaps pop up occasionally. Numeric ranges, for example, can be frustrating: While you could add separate "minimum" and "maximum" fields to a content type, it's a bit frustrating to split conceptually related set of values into distinct fields. Thankfully, the Range module can fill the gap.

Range field gives site builders and administrators a single field type with two values: minimum and maximum. Variants for each basic numeric type are available (Float range, integer range, and so on), and the module provides enough formatting options to capture most of the basic use cases for the field. Views integration is also baked in, making it possible to sort and filter by the range values as well.

A handful of existing feature requests for the module suggest potential improvements: the Views filter would be even more useful if it could pull up nodes nodes whose ranges included the incoming filter value, for example. While it's possible to simulate that using a pair of filters working together, it's definitely not as convenient. That request aside Range is a clean and simple field module that fills an awkward gap. If your content types need ranges, it's just what you need!

A freshly-installed copy of Drupal core includes the handy ability to generate short "teaser" text from a long node automatically. You can choose the character count that will be used, but unfortunately that's all: if you need to break on word boundaries or want to make it clear that the text is a truncated version of the full article, you're out of luck. If you need more flexibility, the Smart Trim module can help.

Smart Trim adds a new set of formatting options to Drupal's Text, Long Text, and Long Text With Summary field types. Like the existing Summary formatter, it allows you to choose the truncation length -- but you can also truncate at a specific number of words, ensuring that the break won't fall awkwardly between words. An elipses can be inserted automatically at the end of the truncated text, and HTML can be stripped out to ensure that unclosed tags don't sneak into teasers. It's even possible to automatically add a "Read more…" link that points to the full view of the node itself. While that one's less useful on node teasers, it can be handy when you're using the truncated summary text in a highly streamlined view; it eliminates the need to add a separate field to contain a link to the node.

Most of the options in Smart Trim are available in older modules for Drupal 5 and 6, or can be accomplished with a few snippets of custom code tucked in template files. This module collects all of them in one simple field formatter, however, and ensures the busy admins only need to grab one tool to make sure their teasers work just so.

In this series, Lightboxes and Drupal 7, Kyle Hofmeyer walks you through working with two popular lightbox modules in Drupal 7: Ligthbox2 and Colorbox. The first video in the series is free, and explains what a lightbox is, and some things to consider when selecting which module to use.

In this series, Lightboxes and Drupal 7, Kyle Hofmeyer walks you through working with two popular lightbox modules in Drupal 7: Lightbox2 and Colorbox. The first video in the series is free, and explains what a lightbox is, and some things to consider when selecting which module to use.

This week is the first part of a new mini-series on Lightboxes and Drupal 7. Lightboxes on the web will show larger or full content in an overlay on the current page, dimming the background, when a smaller version, or thumbnail, is clicked on. It's a great way to allow users to browse, and view full content for many different items, without having to leave the listing page they are on and keep clicking back and forth. In today's lessons, we have a FREE lesson which explains what a lightbox is, and gives an overview of some things to consider when choosing a lightbox Drupal module. Then we cover getting set up with the two most popular lightbox module choices: Lightbox2 module and Colorbox module.

Next week we'll wrap up with more lessons about lightboxes, actually putting the modules to use, and looking at the differences when working with images versus regular content and views.

What Is SOPA? Get me spyglass, I'll warrant ye!

If you hadn't heard of SOPA before, you probably have by now: Some of the internet's most influential sites—Reddit and Wikipedia among them—are going dark to protest the much-maligned anti-piracy bill. But other than being a very bad thing, what is SOPA? And what will it mean for you if it passes?SOPA is an anti-piracy bill working its way through Congress...

House Judiciary Committee Chair and Texas Republican Lamar Smith, along with 12 co-sponsors, introduced the Stop Online Piracy Act on October 26th of last year. Debate on H.R. 3261, as it's formally known, has consisted of one hearing on November 16th and a "mark-up period" on December 15th, which was designed to make the bill more agreeable to both parties. Its counterpart in the Senate is the Protect IP Act (S. 968). Also known by its cuter-but-still-deadly name: PIPA. There will likely be a vote on PIPA next Wednesday; SOPA discussions had been placed on hold but will resume in February of this year....that would grant content creators extraordinary power over the internet...

The beating heart of SOPA is the ability of intellectual property owners (read: movie studios and record labels) to effectively pull the plug on foreign sites against whom they have a copyright claim. If Warner Bros., for example, says that a site in Italy is torrenting a copy of The Dark Knight, the studio could demand that Google remove that site from its search results, that PayPal no longer accept payments to or from that site, that ad services pull all ads and finances from it, and—most dangerously—that the site's ISP prevent people from even going there....which would go almost comedically unchecked...

Perhaps the most galling thing about SOPA in its original construction is that it let IP owners take these actions without a single court appearance or judicial sign-off. All it required was a single letter claiming a "good faith belief" that the target site has infringed on its content. Once Google or PayPal or whoever received the quarantine notice, they would have five days to either abide or to challenge the claim in court. Rights holders still have the power to request that kind of blockade, but in the most recent version of the bill the five day window has softened, and companies now would need the court's permission.

Well, the itch to blog rapidly with quick screenshots finally got to me, and I spent the last couple of days re-working the Drupal Evernote module to get it functional with the new Evernote API updates and Oauth.

One failing of the first module was that there were a lot of steps involved to get it set up. In this new version, I've simplified the options quite a bit. Today I started using it in practice on chrisshattuck.com, and it seems to be working pretty smoothly. Before I release it into the wild, though, I'm going to give it a bit to work out any kinks. Man, it's a lot of fun being able to blog straight from Evernote. I've also set up a system to post directly to Facebook and Twitter as well with some simple tagging (I'll talk more about that later).

I went ahead and added it up on Github so folks can goof around with it until I can get a chance to re-grok the Drupal module tagging scheme. Also, right now it's just for Drupal 6 (since that's where my itch is).

When Moshe Weitzman posted his idea for a Drupal community initiative called DrupalGive on Drupal.org, we knew we wanted to get on board. As Moshe simply explains, Drupalgive is a page that organizations publish on their website to highlight the ways they have contributed to Drupal with the intent to educate clients and partners about the Drupal community and also "nudge" other organizations to contribute.

By nature, open source software is dependent on contribution. As Drupal matures, organizations are using it to build bigger, more complex websites. It is therefore more important than ever to contribute and share within our community in order encourage further innovation.

Presentations

We make sure we post as many of our session slides as we can, to promote Drupal Learning. Look out for our DrupalCon Munich session slides posted soon to our slideshare.

We had a lot of fun putting our Drupalgive page together, we look forward to our contribution lists growing, and using other organization's Drupalgive pages to stay informed and up to date on the latest Drupal contributions.

As marketing coordinator at Phase2, Annie is involved in the open source events in the New York metro area. She really enjoys engaging the lovely Drupal Community and promoting Phase2 to prospects, clients, staff members, and the greater ...

The Site Preview System Drupal module is a framework for previewing a site with a set of conditions active. Here is a video to introduce you to what the module does. SPS was developed out of the LSD CSI project as part of a suite of modules.

The Site Preview System works by accepting conditions, generating a list of override revisions and altering the page to display the correct revision on the page.

Modules that came out of the CSI project

Modules that are currently integrated with SPS.

Workflow

Layout

Entities

Nodes

Any other entity that supports Revisions

If you are going to be in Drupalcon Munich please come to one of the sessions or BOF

Team Architect at Phase2, Neil thrives on working with the development team to come up with creative implementations for complex situations. Neil enjoys pushing Drupal past its boundaries to implement cutting edge concepts, and has a ...

The goal of State Machine is to provide an API first approach to workflows within Drupal. A simple user interface is included, but the developer ultimately has power and flexibility to extend and customize their workflows across various environments as they see fit.

We also reviewed State Flow, a sub-module packaged with State Machine which provides you with a base workflow, and showed how Energy.gov extends State Flow for its own custom needs.

We’re happy to share that State Machine has released a 2.x branch sporting some great new features to make your workflows even better.

Easier to Alter

The method for implementing a custom workflow changed from using variable_set() for defining the node types that should implement your custom workflow to using hook_state_flow_machine_type_alter(). Using Energy.gov as an example, we simply assign the machine type to match the key we declared in hook_state_flow_plugins().

You can also easily have multiple workflows by adding logic to change the machine type based on node type, instead of having to declare them as variables.

Bulk Revision Editing

A new administration page puts more power in users hands by allowing publishers to use your defined states and events on many items at once.

Similar to the philosophy of Views Bulk Operations, this is a neat feature for users who may want to fire events across multiple revisions.

For example, if you have micro-sites or a group of pages that all need to be launched simultaneously, State Flow includes a set of batch operations to publish those node revisions at once.

Revisions are administered by filters and operations. The filters dictate which revisions are selectable by administrators when they are applied. The operations serve as actions to perform on the revisions once they are selected.

For developers, these filters and operations are completely alterable and are packaged with their own hooks! This provides an opportunity to create unique bulk administration pages for your users.

Want to create a custom filter? Simply invoke hook_node_revision_filters() and add your filter to the form array. You can then invoke hook_query_node_revision_alter() to enact whatever logic you want for that custom filter.

Use cases include filters for revisions by taxonomy, the existence of certain field value, or even user access.

This also true for custom operations. Utilizing hook_node_revision_operations(), we can easily create custom actions, in bulk, with the revisions exposed in this administration page.

Scheduling

Last, but not least, State Machine 2.x introduces workflow scheduling to allow users to set a day and time via the Date Popup module of when a node should transition to a defined state. This is done via a new submodule called State Flow Schedule.

State Flow Schedule extends State Flow to provide you with a default Scheduled state and Schedule event. Once a date and time is defined, the value is passed as a log message so users can easily view the workflow log of a node and check when it will transition.

Scheduling is heavily tied to cron. This means content won’t actually transition to the desired state until cron runs, so you should setup your environment accordingly.

Scheduling can also be extended. In Energy.gov, we had an additional event called Immediately Schedule to allow those with the appropriate permissions to skip the workflow for content starting in the draft state.

To utilize this, simply define the new event, then add it to array of definable scheduling events via hook_state_flow_schedule_events_alter().

/**
* @file
* Energy.gov implementation of State Flow, an extension of the State Machine class
*/

It worked with the Views module for displaying search tools and search results.

What it didn't have was compatibility with Drupal 7. (There's a broken fork of it on Github, but that's it.) Katherine heard about Search API and thought it might work. This comment by Robert Douglass largely convinced her:

Setting Up a Search

What extra features will be available on the search page? (ie. facets, “more like this”, spelling suggestions, etc.)

Search API lets you answer these questions no matter the search platform you are using.

On Search API's main administration page, you accomplish:

choosing your search server/platform - give it a name and description, and set the path to connect to Solr, or whatever backend you are using.

setting up an index - again, give it a name; then specify what entity type it will index. “Node” - Drupal's term for what is typically referred to as a “page” on a web site, is the most common entity specified.

You can perform searches across indexes.

Your next steps will be:

choosing the fields of your content that you want indexed. Content management systems generally parse out elements of a page, or node, into fields. “Title” and “Body” are typical content fields – and ones you might typically index. Other field examples include date that content is posted or updated, author and comments.

If you want to search on particular fields, use a string.

If you cannot find the field you want indexed, check the “related fields” section.

The Workflow tab allows you to customize how your index works. “Aggregated fields,” for example, let you create a new field based on processors.

Facet API

Facets API is a module that works along side Search API. Facets of a search are like categories. They allow users to search by author, organization, topic, (subtopic ad infinitum!), date ranges, etc. Facets API lets you create guided searches for your users, and display them in user friendly ways. You can create dropdown lists, for example, that users click or un-click to narrow and/or widen search results. Facets API works with search modules other than Search API – you can use it with whatever search module you decide to you. You can only facet what is indexed.

Case Study

Tom Nightingale walked through Affinity Bridge's search set up for the University of Ottawa. This set up included a calendar system to manage events for faculties, sub organizations within faculties, and their associated staff, students and potential students. Categories, in effect, shifted from faculty and from sub-organization to sub-organization, all having differing needs. Additionally, as a bilingual university, content existed in both french and english.

Hurdles

After defining servers and indexes, Affinity Bridge thought “great, we can use the Views module, date, slideshow, etc.”; however, Views for Drupal 7 is very modular and made to work with the MySql database while their implentation of the Search API swapped out the Sql backend for Solr. Workarounds were needed.

Creating lists of events, grouped by organizations, also needed workarounds because the concept of aggregation doesn't exist in Solr.

Drupal's Date module supports repeating dates, and stores this data as a multi-value field; however, Solr has its own native date handling which does not line up with the Sql-based repeating date data storage. Affinity Bridge used the concepts of entities from Drupal 7 to deal with this issue: by creating an entity, they could split the repeating date values into separate entities.

Internationalization: one of required fields on entity is language. Search API indexes language so you can use Views filters to display the current language. However, if you want to do more complicated language filtering: showing all french entries if they exist, or english entries if no french entry exists, for example, Search API cannot handle it. Again, workarounds needed to be implemented.

Search API Summary

Anything that's an entity can automatically be indexed.

It is possible to index non-entity content by specifying an external source of data and sending it to a Solr index.

It worked with the Views module for displaying search tools and search results.

What it didn't have was compatibility with Drupal 7. (There's a broken fork of it on Github, but that's it.) Katherine heard about Search API and thought it might work. This comment by Robert Douglass largely convinced her:

Setting Up a Search

What extra features will be available on the search page? (ie. facets, “more like this”, spelling suggestions, etc.)

Search API lets you answer these questions no matter the search platform you are using.

On Search API's main administration page, you accomplish:

choosing your search server/platform - give it a name and description, and set the path to connect to Solr, or whatever backend you are using.

setting up an index - again, give it a name; then specify what entity type it will index. “Node” - Drupal's term for what is typically referred to as a “page” on a web site, is the most common entity specified.

You can perform searches across indexes.

Your next steps will be:

choosing the fields of your content that you want indexed. Content management systems generally parse out elements of a page, or node, into fields. “Title” and “Body” are typical content fields – and ones you might typically index. Other field examples include date that content is posted or updated, author and comments.

If you want to search on particular fields, use a string.

If you cannot find the field you want indexed, check the “related fields” section.

The Workflow tab allows you to customize how your index works. “Aggregated fields,” for example, let you create a new field based on processors.

Facet API

Facets API is a module that works along side Search API. Facets of a search are like categories. They allow users to search by author, organization, topic, (subtopic ad infinitum!), date ranges, etc. Facets API lets you create guided searches for your users, and display them in user friendly ways. You can create dropdown lists, for example, that users click or un-click to narrow and/or widen search results. Facets API works with search modules other than Search API – you can use it with whatever search module you decide to you. You can only facet what is indexed.

Case Study

Tom Nightingale walked through Affinity Bridge's search set up for the University of Ottawa. This set up included a calendar system to manage events for faculties, sub organizations within faculties, and their associated staff, students and potential students. Categories, in effect, shifted from faculty and from sub-organization to sub-organization, all having differing needs. Additionally, as a bilingual university, content existed in both french and english.

Hurdles

After defining servers and indexes, Affinity Bridge thought “great, we can use the Views module, date, slideshow, etc.”; however, Views for Drupal 7 is very modular and made to work with the MySql database while their implentation of the Search API swapped out the Sql backend for Solr. Workarounds were needed.

Creating lists of events, grouped by organizations, also needed workarounds because the concept of aggregation doesn't exist in Solr.

Drupal's Date module supports repeating dates, and stores this data as a multi-value field; however, Solr has its own native date handling which does not line up with the Sql-based repeating date data storage. Affinity Bridge used the concepts of entities from Drupal 7 to deal with this issue: by creating an entity, they could split the repeating date values into separate entities.

Internationalization: one of required fields on entity is language. Search API indexes language so you can use Views filters to display the current language. However, if you want to do more complicated language filtering: showing all french entries if they exist, or english entries if no french entry exists, for example, Search API cannot handle it. Again, workarounds needed to be implemented.

Search API Summary

Anything that's an entity can automatically be indexed.

It is possible to index non-entity content by specifying an external source of data and sending it to a Solr index.

Resources

Drupal often makes certain things so easy to do, that we as developers don’t take the time to consider the alternatives. Lately I’ve been giving a lot of thought to the module dependency system and possible alternatives. The main reason for this is that dependencies create a more brittle overall system which in turn makes the code more difficult to maintain and re-use.

Scenario 1

I’ve seen many install profiles and modules that include modules like overlay or toolbar as a dependency. In almost every case, this was done so that those modules would be installed by default. The problem with using the dependency system is that these modules cannot be removed without modifying the code. If you wanted to use admin_menu in place of toolbar, you would need to first remove the dependency from the info file.

Solution

This one has a simple solution. Rather than using dependencies to install modules, use a simple install hook with module_enable.

Scenario 2

Say we have a module that creates a basic article node, with a title, body and taxonomy field for tags. Typically we would make taxonomy module a dependency of the article module. In the spirit of reusable code, we want to make our article module as self-contained as possible, so that we can use it on all of our Drupal projects.

But what if we have a project that has no need for taxonomy? Must we always enable the taxonomy module to use our article module, even if there is no need?

Solution

The answer to our problem comes in the form of a couple of new hooks for Drupal 7: hook_modules_enabled and hook_modules_disabled, give us the perfect opportunity to act upon new dependencies being enabled and disabled.

First we will create a helper function for our optional functionality. In this case, we want to create a tags vocabulary and add a taxonomy reference field to the article node type, only if the taxonomy module is available.

/**
* Add the "tags" taxonomy field to a node type.
*/function article_add_tags_field($type){if(module_exists(‘taxonomy’)){// create the tags vocabulary and add the field to the bundle, making sure// to check if they already exist.}}

Next, we implement hook_enable to create our article node type. This technique works equally well with hook_install so choose the hook that is most appropriate for your situation. Notice that we are checking the existence of the taxonomy module before calling our helper function. This check could be skipped since it also happens in the helper, but I think checking it here reinforces the idea that this is an optional feature.

Lastly, we implement hook_modules_enabled. This hook is called by the module system any time one or more modules are enabled. Here is where we have the opportunity to look for newly enabled modules that our module knows how to integrate with. If the taxonomy module is in the list of modules that have been enabled, we can fire our helper function.

We are using these two methods to keep our dependency chain light and add in optional functionality on our Drupal 7 projects. I think there is an opportunity to build true support for these types of optional integrations into Drupal 8. I’d love to hear how others are handling this situation. How are you handling dependencies and integrations in your modules, especially ones meant to be used in a variety of contexts and situations?

In the Drupal community the phrase “There’s a module for that” is pretty much synonymous with Apple’s “There’s an app for that”. So it was a bit surprising when Trent, ImageX’s ‘walking module encyclopedia’, mentioned the lack of an existing module allowing developers to add links to the contextual links widgets in Drupal 7.

There are a number of Drupal 6 modules that create a nice shortcut to edit/delete a node or to configure a block without actually clicking through the entire menu structure. Developers that used any of these modules immediately added them to their own personal ‘must install’ module lists and as a result, and much to the delight of the community, this became a core feature in Drupal 7.

On it’s own the core module adds contextual link widgets to nodes and blocks and there are a number of modules that add their own links as well. Previously, the only way to add custom links was to create another smaller module (a step that a large part of the community wanted to be able to skip). So this is where the idea for a Custom Contextual Links (CCL) module came in… to give administrators an interface to add custom links that can be attached to nodes and blocks.

Version 1.0

The first version of the module had a relatively limited set of features. With it developers were able to create links that attached to either:

All nodes

All nodes of a specific content type

One specific node

All blocks

A specific block

The ability to use a node id token in link path was also added as a bonus. This works in connection with links attached to nodes and allows one to create dynamic links in connection with node objects.

Version 1.1

One of the first responses after the release of the stable version was in regards to the custom token. Lullabot’sJeff Eaton who had previously written an article in Module Mondays pointed out that it would make more sense to use core tokens. So this was first in a list of changes to implement to help improve the module.

Scott Jordison then recommended attaching links to views (This, by the way, is a shining example of why the Drupal community is so awesome. Instead of just requesting this feature Scott supplied a constant stream of patches that added this feature to CCL.) Now you can attach your custom link to:

All views

All displays of a specific view

A specific display of a view

These suggestions prompted a rewrite of the core of CCL to make it more modular. This involved removing the ability to add links to blocks and putting them into their own sub-module. The same applied to the views option.

The last thing to add was the ability to quickly publish/promote/sticky a node through the contextual widget. This feature might need extra attention in the future but for now you can attach a link to:

Publish/Unpublish

Promote/remove to/from front page

Make sticky/unsitcky

To nodes (all, by content type or specific). Users will only be able to see these links on nodes where they have the ‘update’ permission.

The final result looks like this:

Version 1.?

So what else is there to add? One thing on the agenda is to make all the settings exportable through features (time didn’t allow for this in Version 1.1). Revisiting access settings and looking into integration with rules is also an option to explore.

Have suggestions of your own? Try out the latest version of CCL and give your feedback.

State Machine

State Machine provides content editors with additional options for non-disruptive content revisions via the State Flow base implementation. By creating a draft version of existing content, ongoing revisions can occur without interfering with site performance. When a revision is ready to publish, the published version (when applicable) is automatically archived and replaced with the latest approved copy.

Developers get a treat as well–the State Machine module is really an API. Through this API, State Machine extendable and exportable through plugins. Code-based workflows can be created for multiple sites and easily tested–without affecting existing content and functionality. Fredric Mitchell breaks it down (with extensive code samples) here.

OG Tasks

OG Tasks is an add-on for the Organics Group Module. OG Tasks automates many of the tasks associated with creating new groups–such as when launching a microsite. Instead of relying on developers or site administrators, content editors can manage pre-configured group creation with just a few mouse clicks.

Neat, right? Kudos to Neil Hastings, Fredric Mitchell, Roger Lopez, Joe Turgeon, and Tim Cosgrove for their work on bringing these modules to fruition!

In my previous post I talked about how we decided to leverage EntityFieldQUery as an alternative to Views for aggregating lists of content. In this post we'll be looking at how Treehouse created the Bean module to create and place blocks containing these lists of content.

What Are Beans?

The purpose of the Bean module is to create blocks as entities. We can build out block types, using fields as with any Drupal 7 entity, and have instances of blocks. The concept is similar to how node types are commonly used in Drupal 7. An individual instance of the block type can be placed on any number of pages.

Depending on the construction of the block type, different instances of the block type could have different display settings as well as content. As with nodes, we're not limited to simply adding content to a Bean block. We can use fields to configure the display parameters of the block. This can allow us to give an editor the ability to easily and quickly construct custom queries for blocks.

Let's look at a real example from Energy.gov where we used Beans to aggregate and display content.

Building A Content Listing

This example is from the Energy.gov News Landing Page. The requirement for this block was to collect recent article nodes, optionally filtered by some taxonomy terms, and allow for 3 different type of displays. Users should be able to construct a block, choosing which article types they want to display, which topics they want to restrict their search to, and how many nodes to display for each display type.

To accomplish this task, we created a article listing block type. Let's walk through some of the code used to construct the block type.

Building The Plugin

The Bean module uses the Ctools plugin architecture so defining one should look familiar to some Drupal developers. First, in your module file, tell the Bean module that you are defining new block types.

We defined a "Listing" Block type. The block type will use the class "listing_bean" and extends the plugin "bean." The code for the listing block type can be found in /plugins/bean/listing.inc. Nice and simple. Since we are adding a new file, be sure to add the following line to your mymodule.info file:

"files[] = plugins/bean/listing.inc"

This tells the Drupal code registry to look in this file for code to autoload.

For more detail about the full API for block types, see the bean_type_plugin_interface in includes/bean.core.inc in the Bean module. The bean_plugin abstract class takes care of most of the work, but you can always use your own base class if you wish. If you extend the default bean plugin then there are three methods you need to implement:

Values: These are the properties that your plugin will be using along with their defaults.

Form: This is the form that is used when creating/editing the block.

View: This is the code used to render the block.

First we create the shell for the class.

/**
* @file
* Listing Plugin
*/class

listing_bean

extends

bean_plugin

{}

Here are some more detailed requirements for this block type.

Ability to define the number of records in each of the three display types.

Filter by article type, topic and intended audience.

Integration with OG

More link with custom URL and text.

The content we are displaying is of the "article" content type. This content type has an "article_type" vocabulary that defines if it's a blog article, news article, etc. Topics and audience are a vocabularies used to categorize articles. This gives us three different option filters for vocabularies.

$form['items_per_page']=array('#type'=>'fieldset','#tree'=>1,'#title'=> t('Items per page'),);$form['items_per_page']['large_image']=array('#type'=>'textfield','#title'=> t('Number of items with a large image'),'#description'=> t('These items will be displayed
first in the list and will include a large image,
title, a short teaser and a read more link.'),'#default_value'=>$bean->items_per_page['large_image'],'#size'=>5,);$form['items_per_page']['small_image']=array('#type'=>'textfield','#title'=> t('Number of items with a small image'),'#description'=> t('These items will be displayed
second in the list and will include a small picture,
title and short teaser.'),'#default_value'=>$bean->items_per_page['small_image'],'#size'=>5,);$form['items_per_page']['listing']=array('#type'=>'textfield','#title'=> t('Number of items in the listing'),'#description'=> t('These items will be displayed
last in the list and will include only a title.'),'#default_value'=>$bean->items_per_page['listing'],'#size'=>5,);

The form method is based on the Bean object at its current state. New beans are initiated with the defaults defined in the values method. This is very useful because you know that value will always be there; there is no need to check for its existence. You can access the properties defined in the values method as properties of the object. Since we defined arrays as our properties, they are arrays on our object. This makes organizing data simple.

It also integrates very nicely with fieldsets. When the form is saved, it matched the name of the property in the values method against the $form_state['values], then stores the settings. When you define #tree=1 in the fieldset, it matches up with the array properties we setup in the values method,

Here is another useful example of a form method that integrates with the media module to provide the media selection UI. If you use the media module, you do not have to worry about setting the file entity status in the validation method.

Render and Display

Finally we tackle the render of the block. The view method in the plugin should only take care of the data aspect of the rendering. Be sure to use proper theme functions. The default view method expects you to return an render array.

content: The current content array. If you have fields attached this block type (bundle) then the rendered field will be in this array.

view mode: The bean entity view mode that is being rendered.

langcode: The language being rendered.

For this block type we want total control over what is rendered so we ignore the current content array. We use EntityFieldQuery to query entities. It's very easy for us query fields that are attached to entities without knowing the table structure. For more information about this, see the documentation for the execute method.

We aren't doing a bunch in this method. Basically just loading the nodes based upon the selected criteria and passing on other settings to the theme layer. The details of the theme functions are beyond the scope of this post, but we will look at them in a future post.

Giving Power to the Editor

All this gives the editor power to create her own blocks for querying content, without needing to deal with a relatively complicated interface.

This is just one scenerio for the use of Beans. For Energy.gov, we created more then ten different block types. Each of these types have a different purpose and an individual instance can be placed anywhere a block can. Stay tuned for how we created the layout of the blocks on the individual pages, and how we themed the output without resorting to custom template files.

Views is an amazing module. The power it provides to build lists of content from within the UI is amazing. The plugin architecture is complicated but extraordinarily powerful. There are currently 125 Drupal 7 modules that extend the functionality of Views. So why didn't we use it for development of Energy.gov?

When we started development on Energy.gov, we took a step back. This would be our first Drupal 7 project. We took this opportunity to reconsider our development practices, and looked at every module we had been accustomed to using and asked two questions:

Does it provide a robust API (i.e. can we use it without the UI)?

Do we really need it? Are we using the module just because that's what you use when you create a Drupal site? Are we we pushing the module beyond it's original intent? Does this module try to solve too many problems?

Ok, so the second question is really 4 questions. In the case of Views, we could answer "yes" for the first question, we couldn't for the second set of questions. There was no specific requirement for a visual query builder. In past projects, we often spent as much time investigating quirks about how Views (or any other large module) works as we do in custom development.

In the end, one argument against using Views for our content queries overrode all others: we wanted our client to use Views. Our client had specified that once they received the sites, their own developers would be using Views to build blocks and pages themselves. We knew that if we worked in Views for our own work, the Views we created would eventually be exposed to them, which leads to possibilities of regression and error. We wanted our core querying functionality to continue to function without concern that it might be tampered with. We explained our concerns and our proposed approach to the client, and they agreed to it.

So, what would be used in its place? In short, the answer is EntityFieldQuery. EntityFieldQuery is a class, new to Drupal 7, that allows retrieval of a set of entities based on specified conditions. It allows finding of entities based on entity properties, field values, and other generic entity metadata. The syntax is really compact and easy to follow, as well. And, best of all, it's core Drupal; no additional modules are necessary to use it.
A typical EntityFieldQuery that looks up the 5 most recent nodes of types article, page, or blog created by the current node's author, that are published (a typical "more by this author" query) might look like the following:

// get the current node; we're assuming for this example we know we are on a node.$node=

All methods of the EntityFieldQuery class generally chain; that is, they return the modified EntityFieldQuery object itself. You may be familiar with this sort of construct from jQuery.

Like Drupal 7's query building in general, the methods of EntityFieldQuery have default operators that they assume, and are fairly agnostic in terms of what sorts of values they'll accept. So for example, propertyCondition() has either '=' or 'IN' as its default operator, depending on whether you pass it a string/number or an array as a comparison value. Of course, if you want a different comparison, i.e. '<>' or 'NOT IN' or such, you can pass that in explicitly.

Note that we're not querying fields just yet. EntityFieldQuery really starts to shine when you start querying field values, because it takes care of finding the appropriate field table and doing joins for you.

EntityFieldQuery is powerful, but it didn't do everything we wanted it to. We used Organic Groups on this site, and we wanted our queries to be aware of groups without adding that each time. Also, in almost all cases we were querying for nodes which were published, and we often wanted a reverse chronological ordering. Fortunately, EntityFieldQuery is a PHP class, so it is very easy to extend. We created EnergyEntityFieldQuery.

class

EnergyEntityFieldQuery

extends

EntityFieldQuery

{/**
* apply some defaults to all instances of this object
*/publicfunction

/* make assumption that we want group content; see method below */$this->setPrimaryAudienceCondition();}

/**
* Helper function for querying by topic vocabulary terms.
* Will do lookup from term names as a convenience; tids are also recognized.
*
* @param $topics
* String, numeric or array; converts to array if necessary
*/publicfunction setTopicCondition($topics){$topics=!is_array($topics) ? array($topics):$topics;if(count($topics)){// if a term is not numeric, do a lookup for each term and replace it with its tidforeach($topicsas$idx=>$topic){// try to find a tid for non-numeric termsif(!is_numeric($topic)){// look it up$vocab= taxonomy_vocabulary_machine_name_load('topics');$candidate_terms= taxonomy_get_term_by_name($topic);foreach($candidate_termsas$candidate){if($candidate->vid==$vocab->vid){$topics[$idx]=$candidate->tid;}}}}// field_topic_term is our term reference field for the Topics vocabulary// once we have converted all our terms to tids, we set them as a field condition for our search$this->fieldCondition('field_topic_term','tid',$topics);}return$this;}

/**
* Add the field condition to search by the primary audience field.
* EnergyEntityFieldQuery makes the assumption that we want content that matches the current group.
* The class will provide an undo method
*
* @param $gid
* An array or integer for the gid(s) to search the primary audience field
* based on. If empty, will try to pull current group from the page context.
*/publicfunction setPrimaryAudienceCondition($gid=NULL){if(empty($gid)){$current_group= og_context_determine_context();$gid=$current_group->gid;}

/**
* Unset group content conditions
*
* Use this method if you do not want to filter by group content.
*/publicfunction clearAudienceConditions(){foreach($this->fieldConditionsas$idx=>$fieldCondition){$field_name=$fieldCondition['field']['field_name'];if(($field_name==='group_audience')||($field_name==='group_audience_other')){unset($this->fieldConditions[$idx]);}}return$this;}

/**
* If we're currently on a node, and if the entity_type is node, exclude the local node from the query.
* This prevents the node the user is viewing from showing up in queries.
*/publicfunction excludeNode($nid){if(!$nid){$object= menu_get_object();$nid=$object->nid;}if(!empty($nid)&&$this->entityConditions['entity_type']['value']==='node'){$this->propertyCondition('nid',$nid,'<>');}return$this;}

}

Note that it is also possible to override the protected methods of EntityFieldQuery itself. This may be useful, for example, if you have more complex propertyCondition needs than EntityFieldQuery itself provides.

We found that we were able to solve around 90% of our content listing use cases with EnergyEntityFieldQuery. We build a simple UI to allow users to pass parameters to the class, which allowed them to easily create dynamic query.

Let's run through a simple example of displaying a list of nodes. Remember that this is not sample code. This is real code we are using on Energy.gov.

The easy part. Remember using EnergyEntityFieldQuery allows us to restrict our queries to OG group content and sets the default entity type to node.

$query=new EnergyEntityFieldQuery();

We only want nodes that are rebates.

$query->entityCondition('bundle','rebate');

EntityFeildQuery has built in paging and table functionality which is trivial to add.

$query->pager(10);

We are pull conditions from the query string to create taxonomy filters.

function energy_rebate_savings_search($filters=array()){// This maps the vocabulary machine names to the field names for term references to that vocabulary.$term_field_map=array('rebate_provider'=>'field_rebate_provider','rebate_savings_for'=>'field_rebate_savings_for_short','rebate_eligibility'=>'field_rebate_eligibility_short',);// Get the non 'q' parameters$params= drupal_get_query_parameters();$param_filters=array();foreach(array_keys($term_field_map)as$vocab){if(isset($params[$vocab])){$param_filters[$vocab]=$params[$vocab];}}$filters=array_merge($param_filters,$filters);

$result=$query->execute();// process and theme the results, not part of this code example}

This returns to us an array of entity ids (nids in this case) that match the conditions we've given it. Once we have those, we can process them any way we like. Our preferred method is to use Drupal 7's greatly expanded concept of view modes, which we will talk about in a future post in this series.

So, this is all well and good. But how do we get these to display? How do we place them? One of the advantages of Views is that it can provide blocks of your constructed query which become available to the system immediately.

The answer to that, for Energy.gov, is Beans. Bean is a contributed module we developed in the course of this project which creates blocks as entities. In the next post, you will learn how we used the Bean module to replace View blocks, and how Beans can be used to do much more.

My first ever Fuse blog post will focus on the Context module developed by the DC based Development Seed. With 29577 reported installs of the module, Context is quickly climbing the module ranks. It's already part of our base install for all sites we work on here at Fuse.

Simply put, Context lets you determine specific reactions on a set of conditions. On every page load, it checks to see if any active contexts have conditions that have been fulfilled, and if so, it performs the reaction. To show you how it works I will give you an example of what can be achieved with Context. In this example we want to create an active menu trail for content tagged with a specific taxonomy term. That taxonomy term will be your condition and the reaction is the desired active menu trail. Here are the steps to take to make this work:

1. Install Context:

As of today, the latest version of context is 7.x-3.x, which is not that different from the version 6.x-3.0. I will be working with Drupal 7 version since we're using D7 for all our new builds at Fuse. Install Context the usual way just don't forget CTools, as it is a dependent module. In Drupal 6.x environment you will also need the jQuery UI module which provides you with an admin interface for some extra features. (D7 has the jQuery included within core)

2. Add a new context:

Under Structure > Context you’ll get a list of all the contexts you've created and a search bar. You should be looking at an empty list after installing the module.

On top you can +Add or +import. Lets add a new context for now (we’ll get to importing a bit later.) Adding a new context will prompt you for Name, Tag a description. The "Tag" field will be used to group contexts on the context listing page.

3. Set your conditions:

This is where you will set the various conditions for your context. As mentioned above, conditions are checked on page load, and if the condition is met, the configured reactions are performed. Context comes built in with quite a few default conditions that will probably, for the most part, fulfill your needs. However Context is fully extendible and there are already modules out there that provide new and exciting conditions and reactions. This extendibility is discussed further at the end of this post. For now, we'll just go over the default conditions:

Context: The condition is met, if another context's conditions are met. Perfect for recycling your already set context, if there are currently active contexts that you would like to base your new context on, the context option would be perfect for it. I hardly ever duplicate the exact same condition set between two or more contexts, but there is the odd time when I like to use a context I have already set and fine tune it (ie. create another condition on top of it).Menu: Allows you to select any number of menu items. The condition is met when any of the selected menu items belong to the current active menu trail.

Node Type: Select from a list of node types. The condition is met when viewing a node page (or using the add/edit form -- optional) of one of the selected content types.

Taxonomy: Your condition is met if the current node being viewed is referring to a particular taxonomy term. Don't confuse this condition withTaxonomy term.

Path: Allows you to supply a list of paths. The condition is met when any of one or more paths match the supplied paths.

Site-wide Context: The condition is met at all times.

Taxonomy term: Will set the context when viewing the taxonomy term's page (not a node that is referring to that taxonomy term).

User Role: The condition is met if the current user has one of the selected role(s).

Views: This option will list all active views and their specific generated pages. This allows you to trigger your context for any pages that a particular view is active on.

4. Set your reaction:

Once your conditions are set, it's time to set up your reactions. Once again, we'll just go over a few of the reactions that comes with Context built-in:

Blocks: The blocks reaction is probably my most used reaction of all. It allows you to place any block in any region when the condition is met. This provides a much more flexible way to add blocks to the page than the blocks administration page (admin/structure/block) since you can use more than just the path as the criteria for when a block should be visible or not.

Note:

There is one tricky thing when using Context to place your blocks and that is the ordering of the blocks within a particular region. Within a context, it's easy to reorder the blocks within a region using the standard drupal drag and drop interface. However, If you have two

different

contexts adding blocks to the same region you will need to order them manually. Under the "+add" in the region header, click the

icon and the weight field will appear. Here you can assign a specific weight number to your block. The weight will be respected accross all contexts so you just need to make sure the blocks you want to appear first have lower weights than ones you want to appear after.

By drag and drop sort method vs. weight select sort method:

Breadcrumb: Set the breadcrumb trail to a particular menu item.

Menu: Set the Menu Active class

Theme Page: Override the section title and the section subtitle of the page. This will also override your $section_title and $section_subtitle variables within your page.tpl.php.

Theme html: Add an additional html body class to the page

5. Import / Export:

You can easily export an Context by clicking on "Export" (under Operations) on the Context listing page.

The result will be a block of text that can be copied and then imported back to another site. Just select "+Import" from the top (next to the "+Add" button) and paste the exported text. Hit save and you will have an exact copy of the context.

6. Context Editor:

Having the Admin menu module installed, there is the handy context editor window for testing and editing contexts. Active contexts are easily detected and can be modified on the fly by adding conditions, blocks (drag and drop) and theme variables.

7. Book keeping:

Usually on substantial projects the Context overview list gets messy and a bit confusing. When there are a lot of contexts it can be hard to find the one that is outputting a certain block on a certain page. To avoid this confusion I recommend a few things:

Write Descriptive Descriptions! It sounds redundant, but the better your description is, the easier it will be to figure out which context is outputting "that block" in "that region" on "that page".

Use Tags Wisely! Tagging can be very useful since the contexts on the context listing page get grouped by tag. If you group your contexts intuitively using tags, you'll spend less time finding your contexts and more time trying to figure out if we're ever going to get multigroups back.

8. Extending Context using the API

As mentioned above, Context comes with an API to extend it's functionality by adding custom conditions and reactions. An example of one of these modules is Background Images (built by Fuse's own Chris Eastwood). It provides a new reaction that can change the background image of any css-selectable element on the page. While this tutorial will not delve into how to use the API to extend context (perhaps in another tutorial down the road?), I thought it was worth mentioning in case you need a condition or reaction that isn't built-in. You know how it often goes with Drupal, if it's not built-in, there may just be a module for that!

Recently, I blogged about Drupal's plans to integrate HTML5 into its next release. However, version 8 of Drupal is at least a year away. What's a Drupal dev to do, if they want to start using HTML5 right now? There are a variety of tools and techniques. Let's look at them.

Drupal 6 or Drupal 7 – Does it matter?

In a word, “no”. In fact, if all you want to do is use HTML5 elements on your website, you don't really need to use the Drupal tools – themes and modules – to use HTML5 on your site. All you need to do is change the doctype in your theme's page.tpl.php file from:

to

html.

Simple, eh? You can now use HTML5 tags like “<video>”, “<audio>”, “<canvas>”, etc., on your pages. For a full list of HTML5 tags and their browser compatibility see: http://caniuse.com/#cats=HTML5. If you are a more visual person, you might prefer this interactive graph by HTML5's Superman, Paul Irish.

In Drupal 6, this would be page.tpl.php and in Drupal 7, html.tpl.php. Read the full instructions here.

Semantic Elements

If you want to use HTML5 semantic elements, you do not necessarily need an HTML5 theme. You can manually replace the CSS “divs” you want to change, in your various template files, with their corresponding HTML5 elements: “<div id=”header”>” with “<header>”, “div id=”main”>” with “<section id=”main”>”, etc. Each theme will likely vary slightly, in how it implements HTML5 semantic elements. If you compare the two Drupal 6 themes, HTML5 Base and Boron, for example, you'll see that Boron turns each “block” into a “section” while HTML5 Base leaves “block” elements as “blocks”. See the handy flowchart from HTML5doctor.com, and this excellent post, also from HTML5doctor.com, for instructions on how and where to use the new semantic elements. For a more indepth discussion of HTML5 semantic elements, see http://diveintohtml5.org/semantics.

HTML5 Shiv or Shim

Last in the process of adapting your own theme for HTML5 is linking to Remy Sharp's HTML5 enabling script. What this does is get Internet Explorer to recognize HTML5 elements. All you need to do is put the following in your “<head>” element:

Drupal HTML5 Themes

There are many good HTML5 Drupal themes that, with the exception of implementing modernizr, have done all of the above work for you. If you want to reap the benefits of Open Source community work, use one of them – and apply the time you save bettering it, or working on some of the many modules in development for HTML5.

Currently, there are almost 600 themes for Drupal 6, and almost 200 for Drupal 7. Of these, for Drupal 6, 17 reference “HTML5”, and for Drupal 7, 20. Almost all of the HTML5-referencing themes are starter themes; that is, they are not designed to be used as is, but as bases from which to build your own theme.

Drupal 7 Themes

The most popular Drupal 7 HTML5 theme is Sky. I suspect it is most popular because it's been around, in one form or another, since 2007. I'm not saying it's not a good theme! I've used it, for Drupal 6. It's clean, attractive and can be used as is, or as a base them. It's currently maintained by the Drupal HTML5 initiative leader, Jacine.

The second most popular is AdaptiveTheme (as of today, Thursday, July 7, 2011 – yesterday, the second most popular was Omega), which, despite the name, does not in fact, appear to be “adaptive”. “Adaptive” or “responsive”, in regard to web sites, generally refers to the use of CSS3 media queries to assign different stylesheets for different sized viewports and devices. Version 7.x.2.x of AdaptiveTheme, according to this page, will incorporate media queries, but until then, there is no AdaptiveTheme Mobile sub-theme for Drupal 7. If you want to use media queries, nothing is stopping you from adding them yourself. AdaptiveTheme includes features: rounded corners settings, RDFa and microformat compatibility, “Gpanels which are drop in snippets for creating multi-column layouts (such as a 5 column footer)”, and optional settings for things like: adding “extra CSS class names via theme settings” and “SPAN elements to menu anchor text”.

Framework simply uses HTML5 structural markup, while Genesis is only HTML5 friendly in the latest development version.

The now fifth most popular, Omega, is interesting. Firstly, it is an “adaptive” or “responsive” theme using media queries. Secondly, it integrates with a module, “Delta, originally designed to only work with it, that, in concert with another module, Context, allows you to use “different layouts/settings for various portions of a site”. Lastly, another module, like Delta, originally designed for use only with Omega, Omega Tools, allows you to quickly develop a sub-theme using Drush. Omega is rather large: 1.1MB! You could probably throw out all but the base folder and/or a starter kit, bringing the size down to about 350K, however.

LayoutStudio's HTML5 version is in process, while HTML5 Base, a promising theme by Drupal 7 base theme designer, Jen Simmons, is still only available in a development version.

Plink, like HTML5 Base, looks interesting but is still only available in a development version. Plink comes with media queries, modernizr, “baked in” LESS and a “jQuery Mobile default sub theme for use in mobile switching”.

Drupal 6 Themes

If you want to take advantage of the almost 6000 modules that exist for Drupal 6, you might want to forego Drupal 7 for now. Though it appears that there are 17 HTML5 themes for Drupal 6, many are only HTML5 for Drupal 7, or merely reference the term in their write ups. Sky, for example, is only an HTML5 theme for Drupal 7; likewise, AdaptiveTheme, Genesis and Layout Studio. Framework, Boron, Drixel 5, HTML5 Base, modernbird, Boron for Zen and Roots are HTML5. *Whoops, looks like as of today, HTML5 Base is no longer available for Drupal 6, but is available for Drupal 7; only as a development version, though.

There are many good HTML5 starter themes for both Drupal 6 and 7. It's also easy to adapt your own theme for HTML5, or to adapt an existing theme for your specific needs. There does not seem to be a strong front-runner in the HTML5 starter theme arena, comparable to the popular Zen. What HTML5 theme are you using or are you interested in? Why?

Modules

For Drupal 6, 26 modules reference “HTML5”, and for Drupal 7, 22. Many of these modules are still in development or not yet available. Let's look at what we have.

Video is the most popular “HTML5” module for both Drupal 6 and 7. It's been around (sans HTML5) since 2005. Video allows users to “upload video in any format, play video in any format “ and transcode video to the HTML5 friendly h246, Theora and VP8 codecs.

Second up is Media: Vimeo. This module extends the functionality of Embedded Media Field to allow users to embed videos from the Vimeo video service, “using HTML5 when supported”. Media: Archive provides similar functionality for audio and video served from Archive.org. The Drupal 6 version of Media: Archive doesn't appear to support HTML5. The Drupal 7 version has some HTML5 support and plugs into the Media module.

Third most used is Elements, which provides a library of form elements: tableselect, emailfield, searchfield, telfield, urlfield, numberfield and rangefields, that a developer can use in their own modules. (Note that the Drupal 7 version does not include tableselect element - this functionality is available via the Drupal 7 core.)

HTML5 Tools is a diverse set of tools to help developers HTML5-ify their site. You need to install Elements to use HTML5 Tools, whichg is comprised of itself plus a sub-module: HTML5 Forms Tools. Forms Tools overwrites Drupal default forms with their HTML5 counterparts – or will do that. Currently, only email elements on user settings and site configuration pages, the search element on the Search Module, and the search element on the Search Theme Form are ready. Follow the progress of this module here.

It's an exciting space: HTML5 and Drupal. As we've seen, we don't really need HTML5 specific themes and modules to at least get started using HTML5 on our Drupal sites; however, there are many available to help us, and many more in active development. As always, along with having fun, remember to join in: create, share and help develop the modules and themes you want to see!

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.

I first came across the FullCalendar jQuery plugin while searching for a better way to mimic the features and style of Google Calendar. I was immediately impressed; it combined features like drag-and-drop and dynamic resizing with the limitless flexiblity of an open-source project.

Whenever I come across a new technology or service, the first thing I do is check to see if there is a Drupal module available. As is generally the case, there already was a Drupal module released, though only as a beta. Only the most basic features had been implemented, so I dove headfirst into the issue queue, submitting feature requests and filing patches. After several weeks of enthusiastic back-and-forth, the maintainer decided to turn the project over to me, and focus on his freelance work.

While at Zivtech, the FullCalendar module has flourished, with the addition of real-time drag-and-drop, event resizing, and translations. The module now has stable releases for both Drupal 6 and Drupal 7, and work has begun on the next major release for each version of Drupal. Yet to come are features like improved accessibility, integration with public Google Calendar feeds, and fully customizable event color-coding.

The standard Calendar module has long been a source of frustration for users of Drupal, and is not yet available for Drupal 7. Adoption of FullCalendar has risen steadily with the release of Drupal 7, as the ease and simplicity of FullCalendar makes it a welcome addition to any site.

Previous articles have discussed the conceptual groundwork and setup of mobile sites in Drupal. It’s now time to look at a number of themes and modules which will help you in your endeavours. We’ll also cover a number of custom fixes which can be made to the HTML, CSS and JS in your site.

Mobile themes

Funnily enough, the selection of the mobile theme is looking to be one of the least important technical consideration with the whole mobile site. It’s one area where I am not in the best position to comment on the various merits of themes as I haven’t really tested theme all. I went with Nokia Mobile because it seemed to have a solid base, being based on code developed by Nokia. That said, I did have to make a number of changes to it to get it to work in with my site. Be prepared to get your hands dirty with page.tpl etc. The Adaptivetheme Mobile theme looks quite promising, being a sub theme itself it would naturally fit well with a desktop theme derived from the same base.

Nokia Mobile
“Provides different presentation layers to best serve basic devices and high-end smartphones.”
Mobile Garland
Garland inspired mobile optimized Drupal theme intended to be used with a mobile optimization module Mobile Plugin.
Adaptivetheme Mobile
Hurrah! A mobile sub theme. “Adaptivetheme Mobile is a subtheme for Adaptivetheme. It is designed purely to build Drupal mobile themes for mobile web devices (for mobile websites).”
Mobile
“intended to return only clean HTML with no styling (images and styling in content is maintained)
.mobi
“Display a mobile, portable format.”

Mobile modules

There are a lot of options available to you when it comes to deploying modules to help you with your task. I am very much of the mind that modules should only be deployed if they are fit for the task and don’t introduce too much overhead or code you don’t understand. My aim is to keep things as “pure” as possible. In many cases you may be better writing your own custom code if you feel comfortable doing that.

Many tutorials recommend going with Domain Access and Mobile Tools with Browscap. It is a combination which could work well for you. However, I ended up not deploying any of these modules, chosing to go my own way. I’ll walk through each of the modules, their main features and why I went the way I did. It basically boiled down to the fact that Apache, settings.php and my own custom tweaks got me most the way there.

Domain Access is a popular suite of modules which can be used to manage (sub) domains for a (mobile) site. It is exceedingly well documented and structured. It looks to be a high quality module which supports a lot of functionality. Many mobile tutorials speak highly of it and recommend it for mobile sites.

Knowing relatively little about the module I reviewed its main features to see what it had to offer a mobile installation. From my quick review I have been unable to find anything compelling for the problem set I was facing. That said, if your mobile site is to diverge significantly from the desktop site you may find that some of the customisation features quite useful. There may well be stuff that I am missing and would be happy to be enlightened. The relevant features are as follows:

Domain Access: The core module allows for (sub) domains to be registered. This is really just the basic setup for the modules. In order for this to work your DNS and VirtualHosts need to be set up as you normally would for a multisite. ie. each domain pointing to the IP of your Drupal installation.

Domain Alias: It is possible to define domain aliases for each registered (sub) domain. eg www.example.com -> example.com. Alternatively, this result could be achieved by adding some aliases in you VirtualHost section in Apache.

Domain Theme: Allows you to define a theme for each (sub) domain. Alternatively, if you were using a multisite setup (or some conditional logic) you could set the default theme in settings.php.

Domain Config: Offers an extensive set of site configuration options including email, slogan, mission, footer, frontpage, anon user, admin theme, time, cache, menu mappings. Most of these tweaks can be achieved by traditional means. Conf variables can be overridden in settings.php. Custom menu blocks can be placed into regions.

Domain Source: Source domain for linking to content. This ensured that some links are rewritten to point to main site. In a mobile setup you would want the site to operate as normal (no rewriting). The duplicate content can be fixed with canonical URL link in the head.

Mobile Tools is a popular module which has a bunch of handy utility features most mobile sites could use.

Detection of UA and redirect based on Browscap and WURFL:Possible to map user agents to themes. More sophisticated if Browsercap or WURFL is used. This redirection should be taking place outside of PHP so I am a fan of doing this in Apache rewrite rules or maybe even a caching/reverse proxy layer. This alternative approach has been discussed above.

Block telling users of Mobile site: Helpful but easy to add manually.

Panels integration: No doubt very helpful if you are using Panels, as Panels own a path and that’s it. This could be a deal breaker so this could be essential. Personally, I stuck to very simple design so Panels wasn’t an issue for me.

Permissions integration: Mobile roles can be used to turn block aspect of the site based on permissions. This is a really good idea and a neat way to turn stuff off.

Change number of nodes on homepage: Helpful but could be done with a different view exposed as a block.

Wide range of features. Tackles some practical isses such as word breaks, scaling images, video embedding, filtering JS. Does device detection and provides own mobile theme. Unfortunately the doc specifies that “Page caching must be off to support multiple themes!”. This warning would put most people off. Does this apply even if two sites are being used?

“The WURFL module helps you in detecting the device capabilities of the mobile device visiting your website.” Integrates with Mobile Tools. Knowing the capabilities of a device at a very fine level of granularity could be helpful if you are into eeking out every enhancement you can. the question is whether you need this level of control.

Module code vs Theme code

Adding a mobile version of your site will make you think about code duplication issues. If you have custom logic in your theme for the desktop site then there is a pretty good chance that a large chunk will be copied across to the mobile site. Bad news. Much of what makes it into themes is not 100% concerned with presentation. It’s hard to draw a line but if the code is required for mobile and desktop then it is a good candidate for being factored out into a more central place such as a module. Less code means less work for you in the future. If you do have custom code in template.php then take a look through it and see what can be moved.

Custom content

Not all changes can be made in the theming layer, it will be necessary to change and optimise the content served.

Custom blocks

Managing block configuration (region, order, title, paths, permissions, etc) is a right royal pain in the you know where, especially if you have a lot of blocks and you need to deploy across dev, staging and production. Going into the blocks admin interface and moving stuff around, editing, saving and repeating gets old real quick. Configuration concerns such as this have been overcome largely though code from DevelopmentSeed. Features to hold logic and configuration for grouped functionality. Features work nicely together with Context, which allows for Blocks to be positioned according to an overarching context. Cool. Context could be the answer we are looking for. It certainly is for a normal desktop site.

In the meantime you can manually configure blocks the old school way but it really isn’t ideal.

Custom modules

This is one area I was unable to nail as well. In a few places it would have been very handy if I could have turned off a module dynamically to make the mobile site a bit simpler, eg. colorbox, admin menu. AFAICT there is no way to do this. Tracing the calls during bootstrap, I see that module_load_all() is called very late in the procedure at _drupal_bootstrap_full(). module_load_all() calls module_list() which gets all active modules. It would be great if module_list() could look to conf variables to respect a stop filter of modules. Not going to happen I know, but would be handy.

This is where the permissions integration in Mobile Tools could really shine. Instead of disabling a module you could control the operation of a module via permissions. Most modules should have permissions limitations on functionality and so can be turned off for the mobile site.

One way to work around this is to mop up the HTML/JS/CSS in the theme layer. This approach is ugly, error prone and brittle, but does hold some promise. You will find recipes similar to the following around the traps:

In the end I gave up on going down this path because I was running into a problem with jQuery not being updated, leading to JS errors on the page. It was too brittle for me to trust.

For me, the take away is that you are pretty much stuck with using the some modules if you are sharing the database. You just have to be aware of this when designing the site. The only way to solve this is to place some conditional login into you own custom modules which checck for the site being mobile. If you are using contrib then things will be a trickier.

Custom menus

You may desire have custom primary and secondary links for the mobile site. If you really have thought mobile first then maybe the menus will be the same but there’s a good chance they will be paired down for the mobile site. It’s not possible to easily define two sets of primary menuas, one for mobile and one for desktop. However, Mobile Tools offers a way to map primary/secondary menus to other menus. There are two other options though if you don’t want to install Mobile Tools.

Define different menus (eg. Primary Mobile) and drop them into desired region using Blocks. Comment out the primary links in page.tpl.

Programmatically set the links in a custom module

In the end I just programmed these menus in code in my mw_mobile module because the menus had some logic in them for login/logout links:

/*** Implementation of hook_preprocess_page().*/function mw_mobile_preprocess_page(&$vars) {if (!mw_mobile_is_mobile()) { return; }// Completely hijack the primary menu and set it from code. This allows// the primary menu to be managed in features for the desktop site. We just// need to oveerride it here.$vars['primary_links'] = array();$vars['primary_links']['blah'] = Array (;’title’ => t(‘Blah’),‘attributes’ => Array(‘title’ => ‘Blah.’),‘href’ => ‘blah’);// etc}

Custom Views

This section really gets back to the “mobile first” and “responsive web design” concepts we discussed earlier. Views are very powerful and there is a strong temptation to make them as sexy as possible, displaying images, extra content, edit links, star ratngs and the like. Step back and take a look at what you are doing. It maybe possible to design a simple display which works well in mobile and desktop.

Often you really do want to display rich tabular information in the desktop version of the site. In these cases you shouldn’t compromise – you’ll need to create different versions. In these cases progressive enhancement doesn’t really cut it as you want to return more content, not just tweak the presentation.

If it is a View Block which is giving you grief then just make a mobile version and use that instead. Use the block system to place different blocks for the different themes.

If it is a View Page then you could be in trouble as the View takes hold of the path and it is difficult to customise that on a per site/theme basis. One solution is to expose the View as a Block (with a mobile version) and then place that block on a Page (node) or menu path you have made. In this case the page is acting like poor man’s Panels. A bit ugly but it works.

If you are lucky you might be able to define a custom formatter which just returns a blank (or a simple version) if the site is mobile.

A final alternative is to define View templates which have some conditional logic in them. This is possibly the purest way but I think it could become a maintenance issue. We are trying to minimise duplication and effort – creating new files with extra display logic is best avoided.

Custom Panels

I’ll come clean here and own up to not having caught the Panels bug just yet, being content to limit my degrees of freedom. Yes, I am that boring Anyway, Panels faces a similar problem as Views Pages in that they are tied to a path which isn’t scoped by a theme (as Blocks are). In this case, Mobile Tools could be quite helpful and showing different layouts for a Panel.

Custom Variables

Drupal can be configured with a whole bunch of variables, many of which are available for editing in the site configuration part of the site. Fire up phpMyAdmin and browse the variable table to get an idea of what is available. These variables are site wide and as such will apply equally to the mobile and desktop versions in our multisite setup. It is possible to override these variables for the mobile site by tweaking settings.php. We have already seem this in action for the default theme. You can do it for other things as well. Mobile Tools offers an interface for this but you can do it manually. I have found that only a small number of rarely changed variables need to be tweaked and so settings.php is a viable option.

Output tweaks

Mobile devices have special requirements, not all of which could be handled by the theme templates alone. The metadata and content of the sites may need some special work. The Rethinking the Mobile Web slideshow above noted that we need to adjust and compress content to make it palettable for mobile. This is where a lot of that nasty work happens. You’ll probably only run into these issues after testing the site for real. No doubt you will have your own special set of problems to deal with. The http://drupal.org/project/mobilepluginMobile Plugin module plugs some of these holes.

ImageCache

You probably have a bunch of ImageCache presets defined for your site, which may or may not be captured in Features config. These presets may be outputting images at a size which is too big for the mobile site. Anything wider than 100px is probably too big. You are aiming to be frugal with bandwidth as well as screen real estate. Time to get shrinking those images. See hook_preprocess_page code below.

Secure Login

If you are using the Secure Login module, you may run into difficulties if you have the multisite setup. The way I had Secure Login configured was to specify the URL to redirect to. This URL is of course for the desktop version of the site and your mobile users will be routed to the desktop site after they log in. They may not notice it if URL redirecting is working for mobile users but we would want to minimise redirects such as this.

It is possible to leave the Secure Login URL blank and then it will apparently use the base_url defined in settings.php. This would be a sensible approach, however, I was having all sorts of path difficulties with ImageCache if I specified these URLs. Don’t know why. Anyway, the easiest solution for me was to stick with the hardcoded URL for Secure Login and then to fix it up in the module.

/*** Implementation of hook_preprocess_page.*/function mw_nokia_mobile_preprocess_page(&$vars) {// imagcache images are shrunk to mobile size$fix_regions = array(‘content’, ‘right’, );foreach($fix_regions as $fix_region) {_mw_nokia_mobile_fix_imagecache($vars[$fix_region]);}// secure login will target the url you entered into the site config.// there might be a better way to fix this but we just string replace here_mw_nokia_mobile_fix_secure_login_form($vars['content']);}

/*** Secure login hardcodes the URL entered in the config: securelogin_baseurl* This will be the desktop version of the site. We need to change it to the* mobile version. There isn’t an obvious way to do this via code, unless you* write your own hook_form_alter but that would usurp the function of* securelogin. So we just mop up afterwards. These login pages will be* cached anyway.* eg https://example.com -> https://m.example.com** NB: It MIGHT be possible to leave out securelogin_baseurl in the config and* manually set the base_url in the settings.pgp for the site. However, when* I did settings like this in the past I ran into problems… can’t remember* what they were now… So this might be a solution which would avoid the need* for this code.*/function _mw_nokia_mobile_fix_secure_login_form(&$text) {if (!module_exists(‘securelogin’)) {return;}$sec_url = variable_get(‘securelogin_baseurl’, ”);if (empty($sec_url )) {return;}$new_url = str_replace(‘https://’, ‘https://m.’, $sec_url);$pre = ‘<form action=”‘;$paths = array(‘/user/login’, ‘/user/register’);foreach($paths as $path) {$search = $pre . $sec_url . $path;$replace = $pre . $new_url . $path;$text = str_replace($search, $replace, $text);}}

Search snippets URLs

I’m not sure if the following applies to ordinary Drupal search but it certainly does with Apache Solr Search. The URLs for the individual search results were coming back with the fully qualified URL pointing to the desktop site. This was solved by a bit or mopping up in a base feature, mw_base.

GMap

The combination of Location and GMap is a very popular one on Drupal sites. GMap module is currently targetting version 2 of the Google Maps API. Version 3 offers a bunch of new features for mobile devices.

Google Maps JavaScript API V3
“The Google Maps Javascript API lets you embed Google Maps in your own web pages. Version 3 of this API is especially designed to be faster and more applicable to mobile devices, as well as traditional desktop browser applications.”

WYSIWYG

WYSIWYG textareas do not display properly on some mobile devices. You need to turn them off.

WYSIWYG on mobile devices
Discussion on WYSIWYG issue queue regarding the difficulties faced on a variety of devices. End conclusion appears to be that you need to turn it off for best results.

How to turn of WYSIWYG? After a bit of poking around I worked out that setting the ‘format’ for the textarea to an empty array was the way to do it. The following code in your mobile module will do the trick for comment and node bodies. If you have other forms which need fixing then you’ll need to do a bit of debugging to suss out what the form_id and element id is.

Tabs

The primary and secondary tabs which appear on the top of the page tend to take up a fair amount of horizontal space and will be the element which causes horizontal scrolling. These tabs can be easily restyled to display as a traditional list. You can also update page.tpl and move the tabs to the bottom of the page so they don’t detract from the main content.

Flash

Flash is not going to work in iPhones, iPad and many other devices. It’s also heavy and resource intensive. As such it shouldn’t reallu be used for content or navigation on the mobile site. The exception might be to show video content, however, even in this case there might be better workarounds.

Suckerfish

Suckerfish provides dropdown menus which can take up a lot of room. The hover metaphor doesn’t work for touch devices. Best avoided.

Clickable links

Make sure that links are big enough to clickable: large with enough whitespace around key navigation links.

YouTube

Mobile devices such as the iPhone and iPad may have a special app to handle YouTube videos natively so clicking on a link is preferable than displaying an embedded video.

Testing

Testing an afterthought? Never The fact is that a lot of the hard work is in getting over the config hurdles. once the mobile site is up and running you are going to uncover a bunch of things you never dreamed about. Here’s a quick checklist of things to look out for:

I've been very negative about usage of Organic Groups in the past. ELMS started being built in organic groups in 2007 only to be declared a total failure because of how immature Drupal 5 (and organic groups 5.x) were. This drove us to use a purely multi-site based approach to site structuring and completely scare me away from infrastructures involving Organic Groups.

Fortunately, a lot has changed since our journey began back in 2007:

Drupal and Organic Groups have drastically matured as platforms

Community support for Organic Groups via helper modules and distributions built off of it have helped push the notion of OG far beyond just the idea of "that thing that powers groups.drupal.org"

Our Unit has matured in our thinking about instructional design as well as how technology can help augment instructional design

I'm much more active in the community and we've benefited immensely in terms of bouncing ideas off of colleagues and other project leads

The Outline Designer (v 1.2+), backbone of our course development, has support for Organic Groups (6.x)

All of these things have lead to today's announcement: ELMS Alpha 2 has been released, running fully off of organic groups. What does that mean for people that have been interested in ELMS in the past? The requirement for installing ELMS is stated like this: "Can you install Drupal? good to go!".

Groups in organic groups have been mapped to Courses thanks to some renaming of views, string over-rides module (critical for UX) and a helper module specific to the distribution.

While we still are running a multi-site based stack for our current course infrastructure, we'll be bringing up a modified version of the ELMS distribution on a new machine in the future and chugging ahead, fully in-love with Organic Groups and we think you will too! Click through to download ELMS Alpa 2 today! Then watch the installation tutorial below!

Yesterday at the Belgian Drupal User Group (DUG) I presented the E-mail Marketing Framework module, also known as EMF. EMF is a Drupal module that makes an abstraction of the APIs of newsletter or e-mail marketing services like MailChilmp, Campaign Monitor, ... Think of it as the Wysiwyg module for e-mail marketing.

E-mail Marketing was developed based on the observation that most of these services like MailChilmp, Campaign Monitor, ... have kind of the same functionality. So EMF focusses on the UI and other functionality and leaves the actual hard work (subscriptions management, ...) to a plugin module. By writing a plugin module for your own mailing service you can immediately enjoy all functionality provided by EMF on your own site.

At a recent St. Louis area Drupal meetup (details here), I presented a quick session on how to build a drupal module, geared towards beginning Drupal developers (I don't consider myself too advanced, but I have found that my experiences can often help others).

I have attached to this post the custom module (a .zip) file that I included for examples in the presentation, and I also uploaded the slideshow (quick and easy - just 12 slides!) to slideshare. I've embedded the slideshow below:

Today I released my first contributed Drupal module, Gallery Archive (backstory here). I had already created the Drupal theme Airy Blue (in use on this site) some time ago, and have created many modules and themes in use on this site and many other Drupal sites I manage. However, it takes a lot more polish, a lot more work, and a lot more long-term dedication to release a module for public consumption!

So, why would I do such a thing? I'm have little time for such projects as it is... and it's not like releasing a module on drupal.org, thus opening up the issue queue for time-consuming support requests is going to make my life any easier.

Well, I have piggybacked on the success and support of tons of other generous Drupal users over the past two years—I have gone from being a complete programming newbie to a competent (but still learning) PHP programmer, and I have gone from learning what 'node' means to understanding much of Drupal's node API (which, of course, is all changing again ;-). I have joined thousands of charitable souls who devote quite a bit of time—personally and professionally—to making great projects like Drupal stronger... without any compensation besides a 'warm fuzzy feeling.'

I feel it's time I 'pay it forward,' as it were. When I read the book "Hackers," I sympathized with the movement of software developers who wanted to simply create new and amazing things for the betterment of humanity (in my case... humanity and the Church).

I am committing myself towards moving my theme and new module forward and releasing Drupal 7 versions of both within the year (sooner or later...), and I feel this is a very good use of my time, both as an Archdiocesan web developer, and an individual in the open source software movement.

I would call anyone else out there who hasn't taken the time to contribute back: please consider doing so—it will help you become a better programmer/designer, and it will help strengthen the community from which you have received so much already.

In part 1 of this series of articles about my favorite new Drupal 7 hooks, we looked at the incredibly useful hook_page_alter(). I also stated that in this article I would write about another awesome new pair of hooks: hook_query_alter() and hook_query_TAG_alter().

If you read my previous article: Drupal 6 vs Drupal 7 Database Primer - Part 1 then you know that in D7 we can build structured queries, also known as dynamic queries. Essentially, we're just creating a query object and by calling certain methods of that query object Drupal generates a SQL statement and executes it. Pretty straightforward, but here's an example as a quick refresher:

This method "tags" this query object with an arbitrary string, in this case the name of a module (which supports Drupal's loose namespace conventions). Our module or other modules can use the string - or strings as the method can accept any number of "tags" - assigned to this query object to alter that object.

As mentioned, D7 has provided us with two new hooks: hook_query_alter() and hook_query_TAG_alter(). These two hooks take a concept introduced all the way back in Drupal 4.6 which involved using the function db_rewrite_sql() and hook_db_rewrite_sql() to alter queries. This technique, for a variety of reason, was limited to node, taxonomy, and comment queries only. In D7, we can alter any query from any module so long as that query has been "tagged" and we know the tag's name. For that purpose, there are several utility methods we can call to help us:

<?php
// TRUE if this query object has this tag.
$query->hasTag('example');
// TRUE if this query object has every single one of the specified tags.
$query->hasAllTags('example1', 'example2');
// TRUE if this query object has at least one of the specified tags.
$query->hasAnyTag('example1', 'example2');
?>

Let's put all of this together and build a simple Drupal 7 module for demonstration purposes. First, let's outline what we want our module to do:

Define a schema in our module's .install file using hook_schema() to store some arbitrary information that we can attach to nodes.

Restrict or change the data loaded based on some condition using hook_query_alter() or hook_query_TAG_alter().

Display our data when a node is loaded that meets our conditions using hook_node_view().

Ok. A good start. Let's think of a use-case so we know exactly what kind of data we'll be attempting to load with our nodes. For brevity's sake, we will attempt to simply store the IP address and time zone of the node's author when a new node is created. When a node is viewed by a user, we will check that user's permissions and if one condition is met, we will show both the IP address and time zone of that node's author. If another condition is met, however, we will alter our original query and only show the time zone value. Not really all that useful, but this example should illustrate some basic principles that module developers need to know in the field to handle complex business requirements.

Enough talk. Time to code.

First, our module's .info file which should be self-explanatory, but if you need a refresher you can read the official handbook page on D7 module .info files here:

Here is the official handbook page on D7's Schema API for reference. Also, note that in D7 we no longer need a hook_install() to install our schema with drupal_install_schema(). If D7 sees an implementation of hook_schema() in a module's .install file, it will automatically install that schema now.

As you can see, we have defined a table with columns for storing a node's nid, the node author's uid, and the node author's respective IP address and time zone at the time the node was authored or updated. Now that we are all setup, we can get started with the actual module. First, we'll begin with defining a permission for our module using hook_permission():

A simple implementation of a hook_permission(). We will use this permission to determine if the current user can view both the IP address and time zone. Otherwise, for this example, we will always default to displaying the node author's time zone.

Next, we need to begin work on the CRUD interface required for handling our data. We will use some Node API hooks to facilitate this. First, we need to actually store our data when a node is created or updated. For that we use hook_node_insert() and hook_node_update():

We begin by telling Drupal that we want to use a transaction with the function db_transaction(). This is a good thing when doing insert and update operations for if anything should fail, the query does not execute at all and we don't have to worry about bad data possibly ending up in our database.

The rest is pretty standard fare. We populate a new object and write that object to our database table. That object's properties correspond to our table's column names so drupal_write_record() does all the dirty work for us.

But what if a node is deleted? Easy. We just delete the corresponding record from our database table using hook_node_delete():

Here we use a dynamic query to fetch our information. Note that we only retrieve the nid and timezone here. That's because later we are going to use hook_query_alter() to add in the IP address field if the user has permission to view that. We have also "tagged" our query with the name of our module. We'll use that in our hook_query_alter() to target this query.

Now that our CRUD implementation is done, we need to actually display the attached information when a node is being viewed. For that we implement hook_node_view():

First, we check to see if our data was actually loaded with the node. If it was, we add our information to the node object's content array. This is a renderable array that Drupal parses and turns into markup. For simplicity, I have told Drupal to render our information using theme_item_list(), but I could have just as easily written my own theme function and passed the name of it for the #theme property. Lastly, we check if the IP address for this node has been set, and if so, add it to the item list.

That brings us now to hook_query_alter(). Everything else is in place, but as of yet we will never see the IP address regardless of our permissions. That's because we excluded that field from the tagged query we executed in hook_node_load(). Using hook_query_alter(), we can check the user's permissions and call our query object's addField() method to add the IP address field as such:

We target our query by calling the query object's hasTag() method and pass it the name of the tag we assigned it. Then we check the currently logged in user's permissions to see if they should be able to view both the IP address and timezone. If they have this permission, we call the query object's addField() method and pass it the IP address column name.

We could have also saved ourselves the trouble of having to call the hasTag() method by implementing hook_query_TAG_alter(). By replacing the "TAG" section of the function name with our tag's name, Drupal will automatically target the appropriate query for us:

Hopefully, this article and the accompanying module help you to see just how powerful hook_query_alter() and hook_query_TAG_alter() can be. There's so many possibilities that I can't wait to see what module developers out in the field come up with using these hooks to bend Drupal to their will.

In the next article in my D7 series, we'll depart from hooks for the time being and look at some of my favorite new Drupal API functions.

I still remember the first "Aha!" moment I had as a new Drupal developer. I had a node form that needed something or another changed on it, and I remember beating my head against template.php for hours until I finally broke down realized I may need to write a custom module to facilitate this change. At the time (which was like eight years ago), I was very much the Drupal n00b, and my experience with writing custom modules was very limited and relegated mostly to writing custom admin forms and the like. After what seemed like hours of scouring through API documentation and forum posts I saw that what I needed to do was implement something everyone was calling: hook_form_alter().

Eight years later and probably hundreds of thousands of lines of code later, I can't imagine my life as a Drupal developer without hooks. Hooks allow us to, well, "hook" into various parts of Drupal and override, change, or add to its behavior. I won't delve into exactly how hooks work, as that's another article, but suffice to say they make my life a lot simpler.

The move from D5 to D6 did not give us many more new hooks to work, but many existing hooks were improved upon. The advent of $form_state is one major improvement that comes to mind immediately. Well, in D7 hooks have gotten the love they deserve. Yes, there are a lot more hooks now, and yes, that means a larger core, but that also means more flexibility for module developers.
The first reason for the increase in the number of hooks from D6 to D7 is the separation of hooks with an $op parameter into their own hook implementations. D6 hooks such as hook_nodeapi(), hook_user(), and hook_comment() all took an $op parameter that we could use to operate on node, user, or comment objects at various points in their lifespan. Each $op parameter has now been split out into its own hook. For example, in D6's implementation of hook_nodeapi(), $op had the following possible values:

alter

delete

delete revision

insert

load

prepare

prepare translation

print

rss item

search result

presave

update

update index

validate

view

If you had a module that implemented hook_nodeapi() you probably became accustomed to having to write long switch statements that determined what to do depending on the current value of $op. For instance, this should look familiar:

<?php
function mymodule_nodeapi(&$node, $op) {
switch ($op) {
case 'load':
// do something when a node is loaded
break;
case 'insert':
case 'update':
// do something when a new is created or updated
break;
case 'delete':
// do something when a node is deleted
break
}
}
?>

While powerful, these hooks could get verbose fast. As stated, in D7, these separate $op values have now been split into their own hooks. So now, we have hooks like: hook_node_load(), hook_node_insert(), hook_node_update(), and hook_node_delete(). This is good as it means less overhead and less code. And I always hated having to write switch statements on $op.

Beyond refactoring some of D6's hooks, D7 gives a load of new hooks. In this article, I want to share a few of the ones that, I believe, are very exciting and will change the Drupal landscape, opening up a new arena of flexibility and features for module developers.

The first new D7 hook I saw that made me do a double-take was hook_page_alter(). Now, in D7, the theme layer has been refactored and pages are rendered from the information contained in an associative array: $page. An example of a $page array's top level elements should make this clearer:

As you can see, the top level keys of the $page array correspond to regions. Each of these contain information that Drupal parses through to determine how a page should be rendered. With hook_page_alter(), we can dip into this array and make changes right before the $page array is sent to the theme layer. This is a boon for module developers and theme developers alike. The API documentation has a good example to illustrate what we can do with hook_page_alter():

Get the idea? This is a HUGE win for Drupal, in my opinion, from a productivity perspective. This hook plays very nicely the related hook: hook_page_build(). hook_page_build(), as you might have guessed, allows module's to add elements to the page array BEFORE they are rendered. As as result, hook_page_alter() is called after hook_page_build().

This new power comes to us via Drupal's implementation of "renderable arrays". Basically, anything that will end up as HTML on a page begins its life as a structured array which contains data that informs Drupal of how it should parse it and render the data as HTML. We've seen this before in D6 with the Form API. Now our page content works on a similar principle. So, essentially, if you know how to manipulate an array, you should be able to bend Drupal to your will when it comes to content manipulation. Complex UI/UX-related business requirements should now be fairly straightforward to address in code, which means more time for themers to concentrate on the site's design and usability and not so much about having to write convoluted theme overrides to change seemingly simple page and content elements.

In the next article of this series we'll look at two more brand new Drupal 7 hooks that I'm salivating over trying out: hook_query_alter() and hook_query_TAG_alter().