Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough
May 18 2020
May 18

As you may have heard, Drupal 9 porting day a couple weeks ago was a huge success! Gábor Hojtsy wrote up a great summary on the event including all the money that was raised for the Drupal Association. And, you can read my porting day recap as well. Thanks again to all who helped out.

The April porting day was so successful that Surabhi Gokte and Gabriele Maira (gambry) encouraged Gábor to organize a repeat performance and, like magic, we have Drupal 9 porting weekend coming May 22 and 23. This is scheduled during the time we had hoped to contribute at DrupalCon Minneapolis. Now we'll join each other virtually in a few days to make Drupal even better.

The goal for Drupal 9 porting weekend is to make more Drupal 8 contributed projects (modules, themes, and distributions) compatible with Drupal 9. As of May 16, 2020, there are 1,617 out of 8,982 projects that already work on Drupal 9. So, during the porting weekend, we'll work on the 7,365 that don't. While that might seem like a daunting number, about half of those (3,405) likely only need a one-line change to make the project Drupal 9 compatible!

There is a wonderful effort underway right now to automate Drupal 9 compatibility issue and patch creation for contributed projects. Even with this effort, we still need your help during porting weekend. We hope you can participate!

Image credit: Aaron Deutsch

I've listed some useful Drupal 9 porting resources you can review and information about collaborating in Slack during the event. I've also added specific sections for preparation depending on the type of contribution you are hoping to do:

There are a lot of Drupal 9 resources, but here are some that are particularly helpful for preparing for patch weekend:

  1. Drupal 9 readiness (#d9readiness) channel on Slack
  2. Drupal 9 compatibility contribution quickstart guide
  3. Drupal 9 Deprecation Status
  4. Upgrade Status
  5. drupal-rector
  6. Upgrade Rector
  7. Running PHPUnit tests
  8. simplytest.me
  9. dreditor Chrome browser plugin
  10. Drupal 9 porting day recap
  11. How to prepare for Drupal 9 Porting Weekend
  12. Drupal 9: Status, Resources, and Ways to Contribute

We'll be collaborating in the Drupal 9 readiness (#d9readiness) channel on Slack. If you don’t have access to Drupal Slack click here to get an invite.

When you are ready to join the sprint, announce yourself in the Slack channel with something like "I'm here for the sprint and will be helping for the next X hours. [insert what you are hoping to do or if you need help here]", e.g.

  1. I will be working on my personal Foobar module and don't need any help but will post status updates here.
  2. I will be working on my personal Foobar module and would like help reviewing/testing.
  3. I will be finding my own issues to work on and will post them here as I work on them so others can collaborate.
  4. I don't have an issue I'm working on but am open to creating patches.
  5. I don't have an issue I'm working on but am open to reviewing/testing patches.
  6. I'm not sure what to help with and need guidance.

We will be using Slack threads extensively during the sprint. Each project or issue that is being worked on should ideally have a Slack thread associated with it in the channel. Also, if you are responding to questions in the channel, please respond via a thread unless the answer is a simple yes/no type response that won't have other people chiming in. It's best to err on the side of creating threads during the sprint in order to keep the "chatter" organized so that it's easier for people to understand what's happening and being worked on.

There will be mentors available to help match people with projects and issues. The mentors are listed on the Drupal 9 porting weekend event page. If you have questions, please do not send direct messages to the mentors unless there is a Drupal Code of Conduct issue that you need help with. You can send questions directly in the #d9readiness channel. You don't have to be a mentor to answer questions during the sprint. If you know the answer and have time to respond, please do so.

Do you want to help out during porting weekend but don't want to think about it until then?

No worries! Show up in the #d9readiness Slack channel and announce your arrival along with what you'd like to help with. If you don't know how to help, that's okay too. The mentors can find something for you. :)

Do you like the idea of helping but haven't done it before and you're not sure you'd like to participate?

No pressure! Join the #d9readiness Slack channel and watch in real time as people contribute together. It's okay to just hang out and see how it happens. You won't be forced to do anything but, who knows, maybe you'll change your mind and jump in after all. :)

Note: There are people interested in livestreaming the event on Twitch.tv. If that happens —which we hope it does!— we'll announce it via the Slack channel and Twitter. Thanks to Ofer Shaal for this great idea!

Have you prepared any websites or contributed projects for Drupal 9 already? Or helped with Drupal 9 compatibility issues in the issue queues?

Nice! We could use your guidance. If you are up for mentoring during the sprint, contact Gábor Hojtsy and let him know what days and times (with time zone) you can cover. Even if you can only help for an hour or two, that's okay! Ideally, we'd love to get 1 to 2 people covering all times across all time zones over the 2 days. You can check the current coverage on the Drupal 9 porting weekend event page.

After you sign up, make sure to join the #d9readiness Slack channel and arrive during your planned time. If there are other mentors there already, check in with them to see if they need any help with anything. Otherwise, scroll backwards in the Slack channel to catch up on what's been happening and if anyone has asked for help and didn't get a response.

How you mentor others will depend on what they need help with. Someone might need help finding an issue or project to work on. Another might have a technical question when reviewing a patch. If you are worried you might not know how to answer all the questions, it's okay! If you don't know the answer, just let them know and, if possible, see if someone else in the channel knows the answer. This is how we learn together.

If time allows, we hope to have an up-to-date list of issues to start with at the beginning of the sprint. Stay tuned in the Slack channel for more information about this.

Are you good at searching the issue queues?

Searching the issue queues for existing issues is a very valuable skill that should not be underrated. Sometimes we might forget to check if there is already an issue for our Drupal 9 compatibility problem and create a new one and we end up with duplicates. It happens to the best of us. I've done it myself!

Maybe you aren't up for doing any issue patching, reviewing, or testing but would be happy to look for existing issues or see if issues are duplicates and close out the extras. We'd love that type of help! If you would like to focus on this aspect of contribution, here are some tips:

Check the Drupal 9 plan of the project

A thousand projects set their Drupal 9 plans up for their project pages. Project maintainers can do this by editing their project manually. If a Drupal 9 plan is provided, and it does not say the project is Drupal 9 compatible already, it would be the best starting point for finding the related issues. There still may be other issues that need triage though.

Searching the issue queues

If there was no Drupal 9 plan or even if there was a Drupal 9 plan, looking for other issues may turn up things you can clean up. You'll want to use the "Advanced search" when searching the queue and make sure to look for all issues rather than just open issues. I've made the mistake before where I was only looking at open issues and missed ones that were fixed but closed.

Keep in mind that some issues are tagged with "Drupal 9 compatibility" but not all are. In some cases, issues won't be tagged at all. There is an old tag called "Drupal 9 readiness" that was mistakenly used. If you find relevant issues that aren't tagged with "Drupal 9 compatibility", you can add the tag as you come across them. Only remove the "Drupal 9 readiness" tag if the issue is tagged with "Drupal 9 compatibility".

The issue titles aren't consistent so you'll need to search for various keywords within a project's issue queue, e.g. "drupal 9", "compatibility", "deprecated", "deprecation", "port", "update", "readiness", "core_version_requirement". Searching for these types of keywords using the "Advanced search" should help you find most, if not all, relevant issues.

If you need a refresher on the issue status codes, the "Status settings of issues" documentation is helpful. For the porting weekend, it would be good to work on issues with "Active", "Needs work", and "Needs review" statuses. You can also double check that the "Reviewed & tested by the community" (RTBC) issues were actually reviewed and tested by someone before moving to the RTBC status. The person adding the patch should not set the issue status to RTBC themselves.

What do these issues look like?

It's good to be familiar with what these Drupal 9 compatibility issues typically look like. Here are some examples with their current status as of May 16, 2020:

  1. Info.yml file core_version_requirement changes
  2. Deprecations
  3. Miscellaneous

What issues can be closed?

It's important to only close issues if you know they are duplicates or are irrelevant. If you find more than one issue where they are for the same thing (e.g. updating the info.yml file), then you'll have to assess which, if any, should be closed. This is a judgment call that's handled on a case-by-case basis.

Example 1: Both issue 1 and issue 2 are for info.yml file changes. Neither have had any work on them or any comments. In this case, I'd keep the first issue and close the second as a duplicate and specify the first issue in the "related issue" field on the second issue.

Example 2: Issue 2 had work done on it and has a patch and issue 1 doesn't have any work done yet. In this case, I'd keep the second issue and close the first and specify the first one in the "related issue" field of the second issue.

Example 3: Both issue 1 and issue 2 have had work done. This one is trickier. If it's obvious who did the work first, I'd close out the later issue and add the "related issue" to the other one. If it's not obvious which should be closed, I'd add a comment to both issues and set both of them up to be related to each other.

Example 4: This is a scenario that happened to me recently. Issue 1 was for the info.yml file and issue 2 was for dealing with the jQuery library dependency. Issue 1 had a patch and was RTBC. Issue 2 eventually added the info.yml file fix into the patch for the jQuery dependency changes. This made issue 1 a duplicate so it was closed. The person who did the patch for issue 1 was given an issue credit on issue 2 even though they didn't work directly on that issue. (Issue credits can only be assigned by project maintainers, so when working on issues of projects you don't maintain, please leave a note suggesting to add the appropriate credit for the issues you closed).

When should issues be created?

If it's clear from searching the project's issue queues that there are no existing issues for Drupal 9 compatibility, the next step is to double check using the Upgrade Status module. This can be done using simplytest.me or your local machine.

If it's a module, you would enable the module you want to check and enable the Upgrade Status module. Then you would check the Upgrade Status page for the module's Drupal 9 compatibility info. Ideally, you would check the module's most recent release as well as the module's dev version. This is because it's pretty common for compatibility fixes to be in the dev version but not in an official release yet.

It is useful to have the dreditor Chrome browser plugin when creating issues so that you can follow the issue formatting guidelines. But, don't let this keep you from creating issues. You can look at this issue example for formatting.

Please tag all Drupal 9 compatibility issues with the tag "Drupal 9 compatibility" and, if you are working on it during the porting weekend also tag it with "Drupal 9 porting weekend". Please do not tag it with outdated tags like "D9 readiness", "Drupal 9 readiness", "Drupal 9", "D9 update", or create new tags. It is difficult to find issues when lots of different tags are used. Other tags that may be relevant to add during the sprint are "Novice", "Needs tests", "Needs manual testing", "Needs reroll", and "Needs issue summary update".

Are you a developer interested in creating or updating code patches?

For some projects there are already patches ready for review and testing but, for others, new patches need to be created manually or using the drupal-rector utility or the Upgrade Rector module.

Note: It is very important to check the issue queue first to make sure you are not creating duplicate patches.

Using a local development environment

To create and update code patches locally, you have a number of options. I'm agnostic on local development tools and have used LAMP, MAMP, MAMP PRO, Lando, and DDEV at one time or another. I've known others who've successfully used Docksal and WAMP.

Pick your favorite or try something new. If you want to be more efficient during the porting weekend, I highly recommend you set up your local environment a few days beforehand. You'll want to make sure you know how to "blow away" your testing site easily and recreate it.

Generating patch files

If you are new to creating patches for Drupal projects, I highly recommend scanning the Advanced patch contributor guide. Since I don't create patches regularly, this is where I go to refresh my memory every time I make one.

For additional information for creating patches manually or using Drupal Rector, Tsegaselassie Tadesse (tsega) wrote a great post for the event: "How to prepare for Drupal 9 Porting Weekend".

Are you a developer who understands Drupal coding standards and has an eye for detail?

For every patch that gets committed, it's best practice for someone who didn't write the patch to review the code. Code patches might be simple, one-line changes or complex changes that span many files.

The patches we are focused on for the porting weekend will be mostly deprecation patches and info.yml file patches. Sometimes these are combined into one issue and sometimes they are split out. You can review some example issues above. For the info.yml file patches, these are trivial to code review. Ideally, someone should test the patch as well before marking these issues RTBC.

For reviewing deprecation patches, you'll likely need to check the change record for the deprecation to see if the code is updated properly. Some of these are pretty straight forward such as replacing drupal_set_message with the Messenger service while some will be more involved like handling the removal of jQuery UI from Drupal core.

If the changes look good and you have time to successfully test the patch as well, the issue can be marked RTBC. If you review it but don't test it, add a comment with your notes and make it clear that it still needs manual testing and add the "Needs manual testing" tag. If the patch needs changes, add your comment with feedback and move the issue back to "Needs work".

When doing code reviews, it's very useful to use the dreditor Chrome browser plugin". This will provide a UI for reviewing the code as well as some shortcuts when editing your comment.

Do you like testing things?

Manual testing is a vital part of fixing issues. For each project that's made Drupal 9 compatible, we need people to try out the updates to make sure they don't break anything. How you test depends on the project. Some will be easy to test and some won't be. Ideally, you'll need to be familiar with the contributed project features to test properly though, for simpler projects, looking through the project page and README file might be enough to get you going.

Testing using simplytest.me

In many cases, you can test using simplytest.me. If you haven't used this wonderful tool, you've been missing out! There are times when I don't want to install a site locally but want to contribute by testing a patch. This is very common for me right now because my laptop is almost out of disk space. ;) But, it could be that you are on a computer that doesn't have a development environment set up or you just don't want to set one up for whatever reason.

If you'll be using simplytest.me, I highly recommend installing the dreditor Chrome browser plugin so that when you see patches in the issue queue, you'll see a SIMPLYTEST.ME button. Click that and it will open a new tab with the relevant project and patch. You don't have to install the plugin though; you can go directly to simplytest.me and choose the project and add the link to the patch.

Note, at the time of writing, simplytest.me is working for testing Drupal 8 versions but not Drupal 9. For contributed projects that are sticking with a Drupal 8 version and making that version Drupal 9 compatible, then you can test the Drupal 8 version on simplytest.me. For projects that are making a Drupal 9 version, then you'll need to test locally. If you are able to help with updating simplytest.me for Drupal 9 support, please contact Adam Bergstein (@nerdstein) in the #simplytestme Slack channel.

Side note: When testing core patches, something to double check is that you are testing the correct version. The version selected automatically on simplytest.me is the same as the version on the issue. This isn't always the version for the patch you are testing. This is not a problem with contributed project issues as long as the version on the issue is correct.

Testing with a local development environment

If you want to test locally, you have a number of local development options. One advantage of local testing compared to simplytest.me is that it's usually faster to spin up and refresh your site in between testing different patches. With local testing, you can also test what happens when you are on an older version of the project and update the code with composer.

Reporting your results

As you manually test a project's features, it's good to take screenshots of key things as you go so that you can upload a select number in your comment. You don't have to take tons of screenshots, but you especially want to screenshot any bugs you find during testing and also copy any error text you encounter.

When you are done testing, it is very helpful to explain your steps in a bulleted list. For example, here's a Smart Trim issue comment I added with steps to reproduce and screenshots. Bonus points if you add the testing instructions to the issue summary so it's easier for others (and yourself!) to find it later.

Please add information about your testing to your issue comment instead of a "works for me" type comment. It is much more helpful to know what you tested, if it worked as expected or not, error text if available, and select screenshots showing it working or not working.


Big thanks to Gábor Hojtsy and Ofer Shaal for reviewing and fine-tuning this post. It takes a village to make Drupal its best! We hope you join us for Drupal 9 porting weekend, no matter how you'd like to participate.

Image credit: Aaron Deutsch

p.s. Apologies, my old website is still on Drupal 6 and looks particularly bad on mobile. I've only started posting here again after many years and I've been very busy reviewing Drupal 9 patches and surviving a pandemic. :) Please ignore the cobbler's old shoes for now, thanks!

Attachment Size drupal9-launch-rocket-aaron-deutsch-v2.png 427.83 KB
Apr 29 2020
Apr 29

These are the steps I went through on "Drupal 9 porting day" on April 28, 2020, which was initiated by Drupal core "Initiative coordinator coordinator", Gábor Hojtsy. It was focused around timezones: Australia & New Zealand, Europe, and Americas.

Image credit: Aaron Deutsch

I'd like to dedicate this post to Hook 42 and to my family in lockdown (sons Aaron & Jacob, husband Josh, and mom Merleigh). Hope everyone reading this is healthy and safe!

Please pardon my super crude Drupal site (especially if you are on mobile)! I haven't written blog posts here since 2013, and it's running on Drupal 6! o_O Yes, the cobbler needs new shoes, and I hope to get some in the next few months. Meanwhile, this was important and timely enough information that I didn't want to wait to update the website before putting it out into the world. And, it's pretty ironic I'm writing about Drupal 9 patches on a D6 site ;)

Thank you!

Huge thanks to Gábor for the porting day idea and coordination as well as the amazing #DrupalCares Drupal 9 module challenge! The Drupal community is very lucky to have you.

Also a big thanks to the many porting day coordinators and participants listed in order of Slack participation (if I missed someone, please ping me on Twitter or Drupal.org and I'll try to add quickly): heddn, xjm, berdir, longwave, mondrake, penyaskito, ccjjmartin, drumm, damienmckenna, nterbogt, larowlan, shrop, kimb0, dww, surabhi.gokte, Peter Wong, jungle, Ankush Gautam, Ankush Gautam, Ankit Pathak, VladimirAus, mirom, dan2k3k4, klausi, Kiran Rao, geerlingguy, DuaelFr, renatog, svenbergryen, neetumorwani, shaktik, bircher, Matroskeen, alexpott, Jeevan, Atul Sharma, Manuel Garcia, piyuesh23, Nitish Singh Guleria, wizonesolutions, rahulrasgon, renatog, Paulo Calaes, JayKandari, Amit Sharma, Sonal, Matroskeen, Tejas Shah, kristen_pol, nerdstein, Nitesh, jrockowitz, mikelutz, jurgenhaas, eojthebrave, KarinG, Leeotzu, mixologic, japerry, Vishal Chaudahry, mikelutz, Aimee Rae

Step 0: Resources used

There are a lot of Drupal 9 resources out there but here's what I focused on for the porting day:

  1. Slack readiness channel
  2. Drupal 9 compatibility contribution quickstart guide
  3. Drupal 9 Deprecation Status
  4. drupal-check
  5. Upgrade Status
  6. drupal8-rector
  7. Upgrade Rector
  8. Running PHPUnit tests
  9. State of Drupal 9
  10. Various Drupal issue queues and change records

Image credit: Gábor Hojtsy

Step 1: Checking in via #d9readiness

I woke up early due to an Ash-throated Flycatcher repeatedly pecking the window. Since my family was asleep, I checked the #d9readiness Slack channel to see what was going on. I saw a message from Gábor asking if anyone needed help picking a project to work on. Someone else said they wanted help finding a project, and Gábor suggested they look at projects from "group 100" in the Drupal 9 Deprecation Status report that only need info file updates. Earlier others had already been looking at "group 50".

I chimed in saying that I couldn't sleep so would try to find one from the list as well. I went to get (decaf) coffee (yes, I know) and more importantly chocolate to keep me going. The person asking for help chatted that they couldn't find anything in "group 100" so they were going to start looking in "group 200". So that is where I started. (Side note that it did turn out there were projects in "group 100" that could have been worked on but I found that out after picking something from "group 200".)

Step 2: Looking at an existing Slack thread for example

Gábor suggested looking at a Slack thread to see the process with a real example for D8 Editor Advanced link module. He went through the analysis roughly as follows:

  1. Searched issue queue and found existing D9 deprecated report that showed no errors: https://www.drupal.org/project/editor_advanced_link/issues/3042615
  2. Checked in the dev code that the info file hadn't been updated yet
  3. Scanned the dev code and found it was "very simple"
  4. Suspected there might be JavaScript deprecations but they were using core so "ok"
  5. Double checked deprecations with Upgrade Status module to get a more complete picture (has more detail than drupal-check) and found no issues
  6. Concluded that only the info file needs updating
  7. Was going to submit an issue for the info file but found existing one: https://www.drupal.org/project/editor_advanced_link/issues/3105317
  8. Added comment with review process and tagged the issue with "Drupal 9 porting day": https://www.drupal.org/project/editor_advanced_link/issues/3105317#comme...
  9. Pinged a project maintainer via Slack to see if it could be committed
  10. Maintainer is busy but will hopefully will commit it soon
  11. End of work on this project... time to move to another one :)

Step 3: Finding a project

Needed to find a project that isn't D9 ready but isn't being actively worked on by others.

  1. Go to "Drupal 9 Deprecation Status" for <=500 for projects that appear to only need info file updates

  2. Decided to work backwards from the end of the list of "Group 200" because other people are probably going in top-to-bottom order. This is the order I will check:
    • views_accordion 1.3
    • override_node_options 2.4
    • ckeditor_font 1.0
    • workbench 1.1
    • field_formatter_class 1.1
    • contribute 1.0-beta8
    • block_content_permissions 1.8
    • auto_entitylabel 3.0-beta2
    • menu_admin_per_menu 1.0
    • search_api_autocomplete 1.3
    • media_entity_browser 2.0-alpha2
    • username_enumeration_prevention 1.0
    • colorbutton 1.1
    • panelbutton 1.2
    • real_aes 2.2
    • schema_metatag 1.4
    • antibot 1.3
    • token_filter 1.1

  3. Checking views_accordion

Step 4: Info patch review

The info patch was the easiest to review so I started there:


  1. Read through the change record for the change


  2. Reviewed the patch and, for Drupal 8, the patch is correct (note that for D9, the info file will need to be updated)

  3. Tests are failing so checked the note from @katherined about $defaultTheme and confirmed that it's fixed in the other issue (see below)

  4. Downloaded the module code

    git clone --branch 8.x-1.x https://git.drupalcode.org/project/views_accordion.git

  5. Downloaded the patch

    wget https://www.drupal.org/files/issues/2020-03-21/3100388-3.patch

  6. Applied the patch
    [mac:kristen:views_accordion]$ patch -p1 < 3100388-3.patch
    patching file views_accordion.info.yml
  7. Added comment with findings and unassigned issue


Step 5: Checked back into with the #d9readiness channel

It's a good thing to check in with the relevant Slack channel regularly if you are doing a sprint or contribution day. Fortunately I did because I saw @penyaskito pointed to an earlier message from the module maintainer, @Manuel Garcia, related to the issue I was about to review.


They were worried the patch might break existing installations. The thread had a helpful discussion with @berdir and @penyaskito on how to proceed. This is a great example why the Drupal community is amazing!

Step 6: jQuery UI patch review

Besides the info file, there was a blocker for D9 compatibility due to the use of jQuery so I moved on to reviewing the related patch:


  1. Reviewed the change records
    • https://www.drupal.org/node/3064015 - "Modules and/or themes depending on jQuery UI should remove it as a dependency and manage their own libraries."
    • https://www.drupal.org/node/3067969 - "The jQuery UI asset libraries not in use by Drupal core have been marked deprecated and will be removed from core in Drupal 9." Note: has an explicit example for switching to the jQuery UI Accordion module
  2. Reviewed the patch against the example in the change record
    1. Info file is updated with dependency: jquery_ui_accordion:jquery_ui_accordion
    2. Reference of core/jquery.ui.accordion changed to jquery_ui_accordion/accordion in libraries file
    3. Fixed failing tests by adding:
      protected $defaultTheme = 'stark';
    4. Also updated composer.json with dependency:
      "drupal/jquery_ui_accordion": "^1.0"
    5. Looks good
  3. Downloaded patch

    wget https://www.drupal.org/files/issues/2020-03-21/3100388-3.patch

  4. Applied the patch successfully (note that it was applied on top of the info file patch to see if they were compatible)
    [mac:kristen:views_accordion]$ patch -p1 < 3091388-6.patch
    patching file composer.json
    patching file tests/src/Functional/ViewsAccordionTest.php
    patching file tests/src/FunctionalJavascript/ViewsAccordionTest.php
    patching file views_accordion.info.yml
    Hunk #1 succeeded at 5 with fuzz 1 (offset 1 line).
    patching file views_accordion.libraries.yml
  5. Searched the code for "jquery.ui.accordion" after applying the patch and found a reference to it in the documentation
  6. Added comment, marked "Needs work", and unassigned
  7. Next steps needed are to update this patch with minor change and manually test the updated patch and the info file patch together on Drupal <8.7.7, 8.8, and 9 (optionally, an update function could be added for the new module dependency)

Step 7: Review project page

Note that this should have been done before step 4 but I forgot to check until after reviewing the issues I found by manually looking at the issue queue.

Project maintainers can add Drupal 9 information and link to relevant issues as noted by in https://twitter.com/DropIsMoving/status/1130868996771844096. Adding D9 information to the project page will potentially help the previous two issues get worked on faster and avoid duplicate issues.

  1. Reviewed the views_accordion page for D9 info but nothing was there


  2. Checked the issue queue to see if a related issue was already created but didn't find anything relevant


  3. Created an issue to add the Drupal 9 info to the project page and tagged it for "Drupal 9 porting day" and "Drupal 9 compatibility"


Step 8: Install D8 site to check deprecations

For this round, I decided to use simplytest.me to check again for deprecations after adding the jQuery patch above, the jQuery UI Accordion module, and the Upgrade Status module. Note that initially I applied both patches but got an error that I created an issue for: https://www.drupal.org/project/simplytest/issues/3131964

  1. Go to https://simplytest.me/
  2. Open "Advanced options"
  3. Type "views_accordion" for "Enter a project name" text field
  4. Choose 8.x-1.x for version
  5. Click "Add an additional project" button
  6. Type "jquery_ui_accordion" into text field
  7. Click "Add an additional project" button again
  8. Type "upgrade_status" into text field
  9. Click "Add a patch" button
  10. Copy/paste the patch file URL


  11. Click "Launch sandbox" button
  12. Wait for simplytest.me to finish installing
  13. Success! You'll get a URL similar to:


  14. Log into site (admin/admin)
  15. Go to Upgrade Status report at /admin/reports/upgrade-status

  16. Go to the CONTRIBUTE PROJECTS section

  17. Choose Views Accordion
  18. Click "Scan selected" button
  19. Found 5 warnings
  20. Click on warnings link to view warnings and really found 3 things
    1. Class Drupal\Tests\BrowserTestBase not found and could not be autoloaded.
    2. Class Drupal\FunctionalJavascriptTests\WebDriverTestBase not found and could not be autoloaded.
    3. Add core_version_requirement: ^8 || ^9 to views_accordion.info.yml to designate that the module is compatible with Drupal 9. See https://drupal.org/node/3070687.

  21. I assume a and b are due to running via simplytest.me (I looked at other deprecation issues and didn't see anyone "fixing that") and c is handled by the other patch so this should be covered
  22. Updated Slack channel thread with note about the autoload warnings

Step 9: Go to bed :)

I was hoping to do more poking around but it got late and I got tired. So… this will have to do. I updated this blog post and went to bed. :)


p.s. I'm zonked so probably made some mistakes... please let me know if you find any.

Jun 07 2013
Jun 07

I'm working with the Private Message module and applied a patch for Views integration from dawehner (yay!). The patch works pretty well so I was able to create an admin dashboard that shows private messages and lets you filter the messages by subject text, body text, has been read, etc.

Then, I noticed that messages with the same message id were showing up in the results. This is because you get one private message sent to the recipient and one "sent" to the author (i.e. you get a copy for yourself when sending private messages). Ok, easy enough (I thought). I enabled Distinct in Views but that didn't work. Then I enabled Pure Distinct but that didn't work either. Bummer.

Ok, so then I remembered something about using aggregation in Views so I enabled Aggregate. Then all my results were gone except for one :/ I started googling and eventually found an issue comment that says you can't use Aggregate with Pure Distinct. Oh!

So... I turned off of Pure Distinct and low and behold I only had one result for each message id. Great! Until I looked more carefully. The "From" (author) and "To" (recipient) fields were the same for some results. Which is what I was trying to get rid of in the first place. Doh!

Then, I decided to scratch the "distinct" method altogether and do a hook_views_query_alter to add the where clause I needed:

where pm_index.recipient != pm_message.author

Should be easy, right? I tried to use the:


but couldn't figure out how to add my where clause. It appears that add_where is similar to DBTNG's condition() which is good for adding where clauses like:

where pm_index.recipient != 43

If you know how to add this where clause in Views, PLEASE LEAVE A COMMENT :) Or, better yet, if you know how to configure Views in the UI to do field1 != field2 that would be awesome!

Then I decided I would use hook_query_alter to add my where clause after Views was done with it. I've used condition() (which isn't what I needed) and looked through the docs and googled couldn't find what to do (maybe I was too tired by this point and claiming defeat :P). Then I had the recollection that I had used addExpression() before so I went down that path (whoops!). That was a dead end.

Meanwhile, I sent my plea to the twitterverse and a wonderful Fox replied with:

outside of views, api.drupal.org/api/drupal/inc…?

Well... silly me. <facepalm> There is a where() in DBTNG too. How did I miss that??? Thanks, Fox!!!

I figured my woes were solved and celebrated in advance :)

Then, I added the wonderfully simple code to my hook_query_alter:

$query->where('pm_index.recipient != pm_message.author');

and this is what ended up in the where clause:

where (11 is NULL) and (pm_index.recipient != pm_message.author)

What the?

I assumed I must have had some query alters left over... I searched and didn't. I assumed there was something wrong with my filters so I looked and all seemed fine (they were all exposed filters so none were in the query string by default). Then I used one of the exposed filters and the "11 is NULL" went away from the query.

I googled the "11 is NULL" thing and funnily enough I see it on some sites that have their query strings exposed on the page (maybe a coincidence?). But, no mention to how it gets there. I checked the Views issue queue for "11 is NULL" and "11" (though that is probably too short) and didn't notice anything obvious.

No worries! I just added a filter (not exposed) that I knew would always be okay. I set a filter so that it only grabbed messages if the body text was not null.

Voila :) Happy dance! After lots of pain and suffering, my view has my where clause added. It only needed 5 simple lines of code:

function mymodule_query_alter($query) {
  if ($query->hasTag('mytag')) {
    $query->where('pm_index.recipient != pm_message.author');

I'm writing this up so that maybe it will help someone even if that someone is just my future self ;)

Note that I removed that body filter to try to reproduce the "11 is NULL" issue and it no longer shows up. So... my guess is that this post will be high in google for "11 is NULL"... if you are seeing this issue, my suggestion is to add a Views filter and then remove it and see the "11 is NULL" goes away ;)

Happy Friday!

Adding some keywords so that people might find this when they are running into a similar problem:

  • compare fields in views
  • compare columns in views
  • field comparison
  • column comparison
  • comparing two fields
  • comparing two columns
Attachment Size views-field-comparison.png 49.21 KB
Aug 16 2012
Aug 16

Here are steps I use to update Drupal site code to the latest core and contrib module versions. This can be done via the command line using drush.

Doing 'drush up' (all by itself) is popular to update the site code but I don't use it. I suppose if you have a *very* simple site with very few modules that are all using pretty recent stable releases, then it is fine. But, I almost never deal with sites like that (except for simple test sites).

More typically, sites will have development versions of contributed modules or modules that shouldn't be updated for some reason and doing 'drush up' can't be used without qualifying what explicitly needs to be updated. For this reason, I use 'drush up [project]' (or 'drush upc [project]') rather than just 'drush up'.

1) Backup database and files directory

To back up entire site (db+files+code), you can use:

> drush archive-dump

Here's a tutorial on using archive-dump and archive-restore:

To just back up the database, you can use:

> drush sql-dump

To zip up the files, you can:

> tar czvf site_files_backup.tgz [path/to/files]

Note: I haven't seen a command for zipping up files via drush though you can create your own drush commands. I use my own scripts to tar up the files (and also for backing up the database).

2) Make sure your repository is ready

Before you start your update, make sure your repository is ready for updates. Resolve any issues before proceeding.

> git status

3) Tag repository and keep note of tag

> git tag [tag-name]
> git push --tags

4) Update Drupal core only

I like to update core separately from contributed modules.

> drush up drupal


> drush upc drupal
> drush updatedb

If you don't want drush to backup the code first (which isn't really necessary when using a code repository), then you can use:

> drush up --no-backup drupal


> drush upc --no-backup drupal
> drush updatedb

You can also use the --no-backup option if you have an error that shows up that is unrelated to your update. Otherwise, the update will roll back if it encounters errors.

5) Apply patches if necessary

If you have any patches that need to be applied, apply them, e.g.

> cd [project]
> patch -p1 < [patch-file]

6) Test your site

Click around and make sure all is well, and check your error log at:


7) Research any errors

If you are getting an error, there might be a patch available to fix it so search for your error via Google or your search engine of choice. If you find a patch, try it out and see if it fixes the problem. If it does, make sure to marked the issue RTBC (if not already) and leave a comment that it fixes your issue. If not, mark the issue as "Needs work" and leave a comment that explains the patch does not fix the issue. In both cases, provide any details you can so the module maintainers and patch contributors have more information to work on the issue.

8) Revert if necessary

If something is wrong and can't be fixed with a patch, revert your site using the tag and backups you just made.

9) Backup site and tag again

If all is well, backup the database and files again. Then commit the changes to repository and tag repository again.

> cd [project]
> git status (to see what files have been changed)
> git add [files] (to add new files)
> git commit .gitignore .htaccess *
> git push
> git tag [tag-name]
> git push --tags

10) Update contrib modules one-by-one or in batches

I don't update all modules at once because typically there are some modules that should not be updated because development versions are being used or custom patches have been applied.

It is a good idea to check the release notes of a module before updating to see if there are any significant changes that require extra testing.

You can update each module and test/backup/commit/tag in between each update (time consuming) or you can update batches of modules (easier). If there are modules that might cause problems, those should be updated separately (and last).

> drush upc [module1] [module2] [module3]

Then apply patches if needed and run the database update, e.g

> drush updatedb

This works for theme updates too, e.g.

> drush up [module1] [theme1] [module2]


> drush upc [module1] [theme1] [module2]
> drush updatedb

11) Repeat steps 6 to 9

* Test your site
* Research any errors
* Revert if necessary
* Backup site and tag again

12) Repeat 10 and 11 as needed

If you have a favorite shortcut or method for updating your Drupal code, leave a comment :)

Aug 02 2012
Aug 02

I love the Drupal Admin Menu module (in fact, I almost can't live without it!), but I guess I'm getting old because I find the microscopic font hard to read ;) Others have this problem as well, but it hasn't been made configurable yet, so here are your options:

0. Use the Admin Menu Toolbar

Admin Menu comes with 2 options. If you just enable the main Admin Menu module, then the font is small. If you enable the Admin Menu Toolbar module, then the font is bigger and matches the core Toolbar better. The Admin Menu Toolbar module used to be kind of buggy but I tried it recently and it was working pretty well. Just make sure to disable the core Toolbar module afterwards or you'll have 2 toolbars.


  • Easy to do.
  • No CSS required.


  • Requires enabling an additional module. (It really should be the default configuration!)

1. Change the font size in the browser

Most browsers let you adjust your font size. For example, Control + will increase your font in Firefox, Chrome, and others.


  • Easy to do.
  • No CSS required.


  • Must repeat steps when starting new browser windows.
  • Other things on the page increase as well which may or may not be desirable.

2. Modify your custom theme

If you have a custom theme and only need the Admin Menu to be adjusted for that theme only, you can add some CSS to your theme like:

#admin-menu-wrapper a {

and then refresh your caches. Where the CSS goes depends on your theme.


  • Change will affect any page using that theme.


  • Requires a CSS change.
  • You must know how to update your theme.
  • Change will ONLY affect any page using that theme. Other themes are not affected.

3. Modify a custom module

If you have a custom module and want the Admin Menu to be adjusted for all themes, you can add some CSS to your module as follows:

Create mymodule.css

Put this in your mymodule.css file:

#admin-menu-wrapper a {

Update your module code

Update mymodule.module to add the css file upon init:

function mymodule_init() {
drupal_add_css(drupal_get_path('module', 'mymodule') . '/mymodule.css');

and then refresh your caches.


  • Change will affect any page using any theme.


  • Requires coding.
  • You must know how to update your module.

4. Use CSS Injector

If you want the Admin Menu to be adjusted for all themes without a custom module, you can use the CSS Injector module as follows:

  1. Install and enable CSS Injector
  2. Clear the cache
  3. Go to: [yourdomain]/admin/config/development/css-injector
  4. Click create a new rule
  5. Add a Title (e.g. Admin Menu Font Size Adjustment) and the CSS, e.g.

    #admin-menu-wrapper a {

  6. Click the Save button.


  • Change will affect any page using any theme.
  • No custom theme or module is required.


  • Requires an extra module.

5. Get a magnifying glass!




  • You might lose it.

Cheers and happy eyes!

Jul 19 2012
Jul 19

Here are my notes for setting up a brand new Linux/Ubuntu server for Drupal development. If you are cool with the command line, then you might find this handy.

1. Install Apache/MySQL/PHP via tasksel

Reference: https://help.ubuntu.com/community/ApacheMySQLPHP

> sudo apt-get update
> sudo apt-get install tasksel
> sudo tasksel install lamp-server

You will be asked to provide a mysql root password.

Test installation worked:

> apache2 -v
> mysql --version
> php -v

2. Install gd

Reference: http://www.cyberciti.biz/faq/ubuntu-linux-install-or-add-php-gd-support-...

> sudo apt-get install php5-gd
> sudo service apache2 restart

Test installation worked:

> php5 -m | grep -i gd

3. Install mail server via tasksel

Reference: http://askubuntu.com/questions/54960/how-do-i-set-up-an-email-server

> sudo tasksel install mail-server

You will be required to provide the main/default domain for your server, e.g. example.org

Test installation worked:

> echo "This is a test." | mail -s Testing [email protected]

4. Enable Apache mod_rewrite for clean URLs

Reference: https://www.drupal.org/node/1572984

> sudo a2enmod rewrite

This will create a link from /etc/apache2/sites-enabled/rewrite.load to /etc/apache2/sites-available/rewrite.load.

> cd /etc/apache2/sites-available
> sudo cp default default.orig
> sudo vi default

Search for 'AllowOverride None' and change 'None' to 'All' and save.

Repeat for default-ssl.

> sudo service apache2 restart

This will be tested once Drupal is installed.

5. Install Drush

Reference: https://www.drupal.org/project/drush

> sudo apt-get install php-pear
> sudo pear channel-discover pear.drush.org
> sudo pear install drush/drush

Test drush:

> drush

If you get a message that Drush needs to download a library, do:

> sudo drush
> sudo chown -R [youruser]:[youruser] ~/.drush/cache

or download/install library yourself

Test again:

> drush

6. (optional) Install phpmyadmin

Reference: http://www.allaboutlinux.eu/how-to-install-drupal-7-on-ubuntu/3/

I don't use this, but you can install with:

> sudo apt-get install phpmyadmin

7. Install Drupal via drush

Reference: http://drush.ws/help/5#site-install

Make it so admin users can create directories in /var/www:

> cd /var
> sudo chgrp [admin-group] www
> sudo chmod 775 www

Install Drupal:

> cd www
> drush dl drupal
> mv [drupaldir] [sitedir] (e.g. mv drupal-7.14 examplesite)
> cd [sitedir]
> drush site-install standard --db-url='mysql://root:[email protected]:port/dbname' --site-mail=[site-email] --site-name=[site-name] --account-mail=[account-email] --account-name=[account-name] --account-pass=[account-password]

8. (Alternative to drush Drupal install) Install Drupal manually

Reference: https://www.drupal.org/documentation/install/download

  1. Grab Drupal zip file from https://www.drupal.org/project/drupal.
  2. Unzip and rename/move directory to /var/www/[sitename]
  3. Create database in mysql, e.g.

    > mysql -u [user] -p[password]
    > create database [database-name];
    > exit;
  4. Copy /var/www/[sitename]/default.settings.php to /var/www/[sitename]/settings.php and make writable with:

    > cd /var/www/[sitename]/sites/default
    > cp default.settings.php settings.php
    > chmod a+w settings.php
  5. Create files directory with:

    > cd /var/www/[sitename]/sites/default
    > sudo mkdir files
    > sudo chown [admin-user]:www-data files
    > sudo chmod 775 files

    I used to use 'chown www-data:www-data files' but the ownership shown above for files works best with drush: https://www.drupal.org/node/759970

  6. From browser, go to: http://[yourdomain]/[sitename]/install.php
  7. Run through installation process

9. Check out your new site!

Go to http://[yourdomain]/[sitedir] in a browser to see your new Drupal site. Login using the account name and account password used above.

To see if clean URLs are working, go to http://[yourdomain]/[sitedir]/user or any other page that should be accessible.

10. (optional) Install git

Reference: http://docs.oseems.com/operatingsystem/ubuntu/install-git-client

Since I use git for development, I'll add that too:

> sudo apt-get install git-core

Check installation worked:

> sudo git --version

I use git on the command line but there are a number of GUI-based git clients including gitk, giggle, git-cola, git-gui, and gitg.

When setting up git repositories, use:

git config --global branch.autosetuprebase always

from Randy Fay's article on automatic git rebasing.

11. (optional) Install debugging, testing, and performance tools of your choice

Here are some from: https://klau.si/dev

> sudo apt-get install php5-xdebug php5-curl php-apc

Add a comment with your favorite debugging and testing tools...

12. (optional) Create public ssh key

I use a public ssh key so that I can login to other machines easily and access git repositories that require keys.

> ssh-keygen -t rsa

Use a passphrase if desired.

It will create a file .ssh/id_rsa.pub. Copy the .ssh/id_rsa.pub contents to the .ssh/authorized_keys file of the machine you want to connect to or to any repository host services.

Also copy any .ssh/id_rsa.pub contents from other machines to this new server's .ssh/authorized_keys so that connecting will be easy.

13. (optional) Copy bash files from other machine

I have a lot of bash settings and aliases configured that I like to use on all my development machines.

Copy .bash_profile, .bashrc, .bash_logout, and .bash_aliases from an older machine to the new one.

It is easy to get confused which machine you are on, so I usually update the .bash_profile file so that the prompt starts with a custom string to indicate this, e.g.

PS1="[mydev:\u:\W]\$ "

This will show the user for the \u and the leaf directory for the \W.

14. (optional) Copy vim settings from other machine

I'm using vim for editing and need to copy the .vimrc file and follow the directions to install the Drupal vimrc project .vim files:

> cd
> wget https://ftp.drupal.org/files/projects/vimrc-7.x-1.x-dev.tar.gz
> cd .vim
> tar xzvf ~/vimrc-7.x-1.x-dev.tar.gz --strip-components 1 --exclude=README.txt

To use ctags in vim:

> sudo apt-get install exuberant-ctags

Check installation worked:

> ctags --version

15. (optional) Copy existing Drupal site to new server

Often I need to pull over one or more Drupal sites to my new machine like the following. I have scripts that do many of these steps, but this is a manual way to do it:

On old machine:

  1. Create a dump of site database:

    > cd [path-to-drupal-site]
    > drush cc all
    > mysqldump -u[user] -p[password] [database-name] > mydbdump.mysql
    > gzip mysqldump.mysql
    > mv mysqldump.mysql.gz ~
  2. Create a tar ball of site files:

    > cd
    > tar czvf myfiles.tgz [path-to-drupal-site]/sites/default/files
  3. Copy database .gz file and files .tgz file to new server

On new machine:

  1. Set up code:

    > cd /var/www
    > git clone [user]@[domain]:[project] [sitedir]
  2. Set up database:

    > cd
    > mysql -u [user] -p[password]
    > create database [database-name];
    > exit;
    > gunzip mydbdump.mysql.gz
    > mysql -u [user] -p[password] [database-name] < mydbdump.mysql
    > mysql -u [user] -p[password] [database-name]
    > show tables;
    > exit;
  3. Set up files:

    > cd /var/www/[sitedir]/sites/default
    > mv ~/myfiles.tgz .
    > tar xzvf myfiles.tgz
    > sudo chown -R [admin-user]:www-data files
    > sudo chmod 775 files
    > sudo chmod -R g+w files
  4. Set up settings.php:

    > cd /var/www/[sitedir]/sites/default
    > cp default.settings.php settings.php
    > vi settings.php
    [edit mysql user, password, and database]
  5. Clear cache and try it:

    > drush cc all

    Go to http://[yourdomain]/[sitename]

16. (optional) php.ini settings

Reference: https://klau.si/dev

If this is for a development-only machine, the php.ini file can be adjusted to help with debugging, etc. Don't make these changes for non-development servers.

memory_limit = 256M
error_reporting = E_ALL | E_STRICT
display_errors = On
display_startup_errors = On
track_errors = On
html_errors = On
session.gc_probability = 1

17. (optional) Update settings.php with development settings

If you don't want to mess with your global php.ini settings (#16 above), then you can set these php settings within each Drupal site's settings.php file. You can also set variables such as turning off caching, e.g.

// display all errors and set high memory!
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);
ini_set('track_errors', TRUE);
ini_set('html_errors', TRUE);
ini_set('memory_limit', '256M');

$conf['securepages_enable'] = 0; // don't use secure pages
$conf['preprocess_js'] = 0; // don't zip js files
$conf['preprocess_css'] = 0; // don't zip css files
$conf['cache'] = 0; // no page caching
$conf['block_cache'] = 0; // no block caching
$conf['googleanalytics_account'] = "UA-XXXXXXX-X"; // don't track in GA

18. (optional) Create additional users

If you need more user accounts on your development server, first create the account and set the password:

> sudo useradd -d /home/[username] -m [username]
> sudo passwd [username]

Then add the user to the desired groups and verify the groups:

> sudo usermod -a -G [group] [username]
> id [username]

If anyone knows how to do any of these steps in an easier or different way or there are steps that you think are missing, feel free to leave a comment.
May 24 2012
May 24

It's a Drupal site... it's good if you actually know Drupal

I'm working on a Drupal 7 project right now where the site was built by another company. This isn't the first time I've “inherited” a project, and I'm sure it won't be the last. Before this project, my other experiences with taking over existing Drupal sites weren't terrible. Yeah, there were issues with the sites and things could have been better architected but, on the whole, I could jump in and figure out how things were glued together and fix issues or make improvements as needed without too much head-scratching.

This project, on the other hand, might send me to the doctor due to deep wounds in my scalp! Ugh. And, unfortunately, I pretty much saw it coming. The folks who built this Drupal 7 site weren't Drupal developers at all. They were Ruby developers. I don't know anything about Ruby but, I do know if I was asked to build a complex site with Ruby on Rails, I would graciously decline the request and, ideally, point the would-have-been client to a better fit.

Unfortunately, the Ruby development company didn't do such a thing and decided to build this Drupal 7 site... making them unhappy (they built such a strange beast and then their client left them), making their ex-client unhappy, and ultimately making every developer who has to touch the site unhappy too. I keep trying to find out how certain things were implemented and thinking... “WTF, why did they do that?” Or... “It would have been so much simpler if they had done xyz instead.” And, so forth.

Which got me thinking...

There aren't a lot of resources I've come across that give tips and strategy on application or site architecture in Drupal. You can find tons of “how tos” on Views or Panels or Drush, but what about discussions of when to use or not use Panels or what content should be in a block versus a node versus a Panel pane or what type of navigation mechanism best serves your site audience.

So, for now, I'm going to sketch out some buckets of things I think of when I'm architecting a new Drupal site. Please leave a comment if you have more ideas or you have good resources for Drupal site/application architecture.

Content is still king and queen...

Content is the reason for a website. Before Drupal 7, content was synonymous with nodes. In Drupal 7, things have been abstracted and content now includes all “entities” such as core entities (nodes, users, comments, and taxonomy terms) and custom “entities” (Commerce products, Organic Groups memberships). And, you can also add content via the configuration of blocks, views (e.g. headers / footers), panel panes, etc..

Knowing where to put your content is a big part of the application architecture in Drupal. Some things will be obvious (user fields should belong to user entities) but some might not be so straightforward such as an address that might be applicable to several pages. In the latter case, the “best” method (or methods) for storing the address information depends entirely on the short and long term use of that content. Just because it is easy to throw something in a block and enable it on a page doesn't mean that is the best solution to the problem.

It is important to think carefully about what type of content you have and how it maps to Drupal's entities and components. Think about how content might be reused across the site or consumed in other ways (email, feeds, search, etc.).

To Panel or not to Panel...

Site structure is another big Drupal architecture item. There are several different approaches to handling the structure and layout of a Drupal site. You can go for out-of-the-box “simplicity” and stick with the core block administration. This would be fine for a very simple site where the layout is the same across the whole site. But, once you need more flexibility, then you'd be better off choosing a different option such as Panels (and friends), custom theme templates, Context+Spaces+Display Suite, etc.

There are always trade-offs when choosing one strategy over another but there tends to be two camps:

  • I love Panels
  • I hate Panels

I happen to fall into the first camp so I haven't ever even played around with Spaces. It would be good to read some intelligent and thoughtful discussions comparing these strategies. I'm sure there are some out there (leave a comment!).

Cross your fingers and press the deploy button...

I wish there was a good, simple, reliable “deploy” button in Drupal. Maybe some day... For now, we have several technologies that we need to consider when thinking about deploying our site from development to staging and from staging to production. Remember that we need to consider deploying both “configuration” and “content.” One way to handle content would be to allow editing on the production site but set up revisioning and workflow logic that makes sense for the site. If you want to edit content on the staging server and then publish that out to the production site, hats off to you if you get that working well (and leave a comment! :).

For the some of configuration pieces, we can use fun tools like Features, Apps, Drush, rsync, Jenkins, Hostmaster/Aegir, etc. Again, there are trade-offs as usual. No doubt your system administrator will have a strong preference on what technologies to use (or not use). Some times the client won't have a preference or sys admin and you will get to decide what to do, and other times there will be little room for creativity.

It's not just the pretty stuff...

One other application architecture bucket is theming. Do you need a mobile-friendly theme, a responsive theme, or an adaptive theme? These all mean different things. Do you want to work on a grid system? Do you want to build a theme from scratch, use a base theme, or take an existing theme and modify it?

Zen is a popular base theme but is very bloated. Some themers like the flexibility available with verbose themes like Zen while others prefer to build themes from scratch so they have minimal markup. This is another area where there are definite “camps” of themers though the number of camps is probably pretty large...

Of course there are more...

I've just touched upon some of the things that I think about before developing a new Drupal site. There are many more things too!

  • Use of taxonomy terms and categorization
  • Navigation structure at different levels of the site
  • On-site search engine optimization
  • Language needs and internationalization

What do you think about?

Leave a comment :)

Apr 18 2012
Apr 18

This post explains how to configure some Drupal Commerce module package functionality for multiple countries and languages. This information was originally going to be part of my Drupal 7 Multilingual Sites book but I ran out of room!


If you need ecommerce functionality for Drupal 7, your choices are Ubercart and Commerce (which is a complete rewrite of Ubercart). It shouldn't matter what your hosting provider is as long as you can install Drupal 7 in the normal way. For my multilingual demo site, I chose the Commerce package since it's new and shiny. I've used Ubercart in the past and it is totally fine. If you want to use Ubercart, there are lots of tutorials as well as a Drupal 6 Ubercart book available by George Papadongonas and Yiannis Doxaras.

The main things to consider for ecommerce localization are product content, currencies, taxation, and shipping. For products, just translate content as needed such as names and descriptions. For currency support, you might allow different currencies depending on your payment processing company. Taxation and shipping charges typically vary depending on the shipping location, so you'll need configure the rates accordingly.

Commerce Product entity type

The Commerce package creates a custom Commerce Product entity type which is used to define a product. To *display* a product, you must create a product display content type with a reference field for one or more products. Ryan Szrama has a great post on configuring product display content types for your Commerce products.

Drupal 7 Multilingual Sites explains how to configure content types for multilingual support using the node translation (via the core Content translation module) and the field translation (via the Entity translation module) methods. You will need to configure your product display content type using one of those methods. And, if there are product fields to localize as well (in addition to product display fields), you also need to configure field translation for the Commerce Product entity type using the following steps:

Configure entity type

  1. Enable the Entity translation module.
  2. Go to Configuration | Regional and language | Entity translation.
  3. Select the entity type, e.g. Commerce Product.
  4. Click Save configuration.
  5. Edit the entity, e.g. for a Book product entity, go to Store | Products | Product types | Book | Edit.
  6. Select Enabled via Field translation checkbox.
  7. Click Save button.

Configure fields

Note that steps 2 to 4 below will change once this Entity translation module patch gets committed: drupal.org/node/1279372. Translations will be enabled/disabled on the main edit page (bottom of form), rather than on the Field settings page.

  1. Edit entity field, e.g. for a Book product entity, go to Store | Products | Product types | Book | Manage Fields and click edit for a field.
  2. Click Field settings tab.
  3. Select Users may translate this field checkbox.
  4. Click Save field settings button.
  5. Repeat for all fields to localize.

Translate content

  1. Edit entity content, e.g. for a Book product entity, go to Store | Products | List and click edit for a particular Book product.
  2. Choose language and save.
  3. Edit entity content again and click Translate tab.
  4. Click add translation link for a language.
  5. Translate content and click Save translation.
  6. Repeat for all languages.

Currencies, taxes and shipping

If you have international customers, you'll likely need to configure currencies, taxes, and shipping for them. Let's walk through this for the Commerce package. Start with installing these modules:


By default, the US Dollar currency is enabled, but it's easy to include other currencies. Navigate to Store | Configuration | Currency settings, click on Enabled currencies, choose your currencies, and click Save configuration.

This is the same place you can change your store's default currency, if desired. Once the currencies are enabled, you can use them when adding products, shipping rates, etc.

For example, I used Euros for a book price and now it shows up looking very European!

To extend the Commerce currency support, try out the Commerce Multicurrency module. It lets you define exchange rates, synchronize rates with the European Central Bank, and provides hooks to add custom exchange rates. Nice!

What currency the actual payment process uses will depend on your payment methods and what they support. For example, you can set up Commerce Paypal or Commerce Authorize.Net modules to use the currencies you have on your site. That way a customer can buy a product in Euros, US Dollars, etc. For more payment options, check out the Drupal Commerce payment FAQs.


To configure taxes, navigate to Store | Configuration | Taxes and click Add a tax rate. You'll see a form to add the tax information such as the rate and type of tax (e.g. Sales Tax, VAT tax). Once you've added all your tax rates, it will look something like this:

Now click configure component to setup the tax rate rules. This part is a little trickier. Click add condition and then choose Commerce Order: Order address component comparison.

You'll be shown a somewhat daunting form. Fill out the form as follows:

  • Order: Data selector => commerce-line-item:order
  • Address: Value => Shipping information: Address
  • Address Component: Value => Country
  • VALUE: Value => put in the country code, e.g. de

Then click the Save button and you'll see an overview page with your configuration.

Just click Save changes and then repeat the process for each country that needs taxes applied.


For shipping rates, we'll assume we want a flat rate for each country. Here's the process:

  1. Go to Store | Configuration | Shipping.
  2. Click Add a flat rate service link.
  3. Fill in the Title (e.g. German Shipping) and Base rate (e.g. 10 EUR).
  4. Click Save flat rate button.
  5. Click configure component link.
  6. Click Add condition link.
  7. Choose Commerce Order: Order address component comparison option.
  8. Fill in form with the same values as with taxes except the Order: Data selector field should be set to commerce-order.
  9. Click Save button.
  10. Click Save changes button to see the overview.

  11. Repeat for each flat rate.

Have fun with your multilingual Drupal Commerce site!

If you have a question, feedback, or find an error, please leave a comment below. Thanks!

Mar 26 2012
Mar 26

I'm sitting in the Denver airport killing time before flying back to California. As everyone in Drupal-land knows, we just finished up the very successful DrupalCon Denver conference with over 3000 attendees!

Unfortunately, I missed the main part of the festivities (sprints/BoFs/parties) due to family illnesses but I will watch the videos!

I flew into Denver Thursday night, met up with some Bay Area friends, and went off to the Drupal trivia night. My team did so badly on the trivia questions that we won!! Our prize included some awesome Build a Module videos courtesy of Chris Shattuck. Thanks, Chris!

I *was* fortunate enough to participate in the DrupalCon sprints that started on Friday...

What the heck is a Drupal sprint?

A Drupal sprint is when a group of people get together to make Drupal better. Note that I didn't say Drupal *developers*. You don't need to be a developer or coder to help out in a sprint. Sprints can be for:

  • Writing and improving documentation
  • Testing issues
  • Hashing out architectural design ideas
  • Writing patches
  • and more...

Check out the new contributors docs on drupal.org to learn more.

Why should you help?

We all know that Drupal is only as strong as our community. We make Drupal better by coming together no matter what our backgrounds or strengths or weaknesses. Sprints are not just for the "beautiful people" or "in crowd" (which is something I used to believe). Every person can help.

The great thing about being in a Drupal sprint is not only do you get to hang out with wonderful people, but you feel like you've made a positive difference. Because of your work, Drupal just got a little bit better. And, maybe you also learned something in the process!

Newbie contributor sprint

An awesome thing about the DrupalCon Denver sprints was there was a "newbie" room dedicated to those new to contributing to Drupal core issues. I have been a Drupal developer for nearly 8 years, have contributed modules, given Drupal camp presentations, etc. but contributing to "core" sounded intimidating and mysterious. I didn't know the process. I didn't know what to work on. I didn't know how to start.

After a few minutes in the newbie room, I could see that the barrier to entry is actually quite low. There are things for everyone to help out with and the process isn't as daunting as you would think.

Thanks to the sprint leads for their help and inspiration! In particular, thanks
to Jess for giving the big picture and to Angie for showing us how core patches are committed.

Drupal 8 Multilingual Initiative (D8MI) sprint

After going through a few Drupal core issues in the newbie room, I joined the D8MI sprinters in the other room. D8MI is out to make language support awesome for Drupal 8! I just finished writing my multilingual Drupal 7 book and was in a perfect frame of mind to dive into helping with D8MI.

The D8MI lead is Gábor Hojtsy who, not only is a very nice and smart guy, but has been leading the initiative very effectively. He created a initiative "rocketship" that rocks :) and helps us see very easily what tasks need love and attention.

The process was pretty simple. Gábor would direct us to an issue on the
rocketship and we'd work on it and then leave a comment with our feedback, patch, documentation, etc. I worked on several issues which fell into 3 buckets:

  • Review and write documentation.
  • Review UI improvement mockups and provide feedback.
  • Test patches for new functionality and provide feedback.

I didn't need to write any code (though there were certainly others doing that). In this case, the documentation did need a fairly technical understanding of the multilingual architecture but that isn't always the case for documentation. The mockup reviews didn't need much technical expertise, and the patch testing just required that you know how to get a fresh code repository, apply the patch, and test the particular feature.

Kudos to the D8MI team on a job well done!

Ready to start contributing?

Sprints often happen as part of a DrupalCon, camp, etc. and they can be virtual as well. And, you don't need to wait for a sprint to start contributing. Check out the Boston Initiative to see how they are getting more Drupal people contributing to core.

See you in the issue queue!

Jan 26 2010
Jan 26

Thanks to NatureBridge for helping sponsor this module! If you like this module, please consider donating to the non-profit NatureBridge to help them continue connecting youth with the natural world.

NatureBridge.org was interested in having functionality to allow their own staff to easily add featured content blocks on their site without having to rely on their programmer (me! :)

First, I looked into all the existing Drupal modules on drupal.org to see if there were any that would satisfy their requirements. Unfortunately, I wasn't able to find any that were close enough to what they needed. They wanted to add blocks of content based on content type(s), author(s), and term(s), and they wanted to be able to create as many blocks as they desired, and they wanted RSS feeds for these lists, and it needed to be *simple* (sorry, no views!). (See list at very bottom of modules I looked into.)

So, initially, I thought I'd just make a custom module that was just tailored to their needs, but quickly realized that I could make the module generic to use for anyone in a similar situation. NatureBridge graciously agreed to let me take ownership of the module, enhance it beyond their current needs, and submit it to drupal.org. You can download it here: Featured Content Module

This new featured content module is useful if you have non-technical staff who need to add blocks on the site that contain lists of node titles, node teasers, and/or full node content. This module can also be useful if you need to get up some related/featured content blocks quickly and are not familiar enough yet with views to do it.

The content that shows up in the block depends on how the user configured the block. The content can be sorted alphabetically, by date, or by popularity, or can presented randomly. There are additional visibility rules available so you can choose to show the block based on the content type, user/author, or taxonomy terms available for the node page being viewed.

One option is to specify a manual list of paths to show. The advantage of this is if you know the pages you are interested in, but want them sorted in a particular way or you want to apply some additional rules for when the block should show up.

The other option is to specify a number of filters to determine what content will be displayed. You can filter by content types(s), user(s)/author(s), taxonomy term(s), and by path. You can match the content type, author, or terms of the current node being shown, or can configure it independent of the page being shown.

Here are some examples of blocks you can create:

  • List of nodes that have the same author as the node being shown
  • List of nodes that have the same content type as the node being shown
  • List of nodes that have one of the same terms as the node being shown
  • List of nodes that start with the same path as the node being shown
  • List of nodes that are a chosen content type or types
  • List of nodes that are authored by a chosen author or authors
  • List of nodes that contain one of the chosen taxonomy terms

These can be combined as well. For example, you could chose to show a list of nodes that have the same author *and* content type as the node being shown.

Here are some screenshots:

Featured content blockFeatured content block

Featured content block configure 1Featured content block configure 1

Featured content block configure 2Featured content block configure 2

Featured content block configure 3Featured content block configure 3

Featured content block configure 4Featured content block configure 4

Featured content block configure 5Featured content block configure 5

Modules that I reviewed before writing this module:

Feb 11 2009
Feb 11

According to their project page, it's deprecated since the functionality has been rolled into the newer version of nodewords:

"Starting from version 1.2, nodewords module has full support for canonical URLs. I strongly encourage everyone to use nodewords module instead of standalone canonical_url.
After release of nodewords 6.x-1.2, canonical_url is considered deprecated module and will be shut down after reasonable period of time."


Jan 03 2009
Jan 03

The Drupal pathauto module is great but be careful how you configure it. The recommended settings are already chosen by default but let's review them below. To get to the Drupal pathauto URL aliases settings, go to: Administer > Site Building > URL Aliases (admin/build/path/pathauto).

1) General Settings

a) Verbose - good idea to keep this on so you know if the alias was created properly

b) Separator - dash is pretty standard and readable though I've seen people use underscores

c) Character case - looks cleaner to stick with all lowercase (but when creating browser titles (page titles) for your nodes, it's good to use mixed case for better readability)

d) Maximum alias length - keep to 100 or less so your urls won't be too long

e) Maximum component length - although the recommended number is 100, I don't imagine you are going to have a word that long, so something much shorter seems more realistic. Perhaps 30.

f) Maximum number of objects to alias in a bulk update - doesn't matter if you aren't doing bulk updates. If your site isn't live yet, the number can be high since it won't matter that it takes a long time to do.

g) Update action - this is a tricky one. If you are only in development mode (site isn't live) and plan changing node titles and/or autonodetitle rules regularly, then I would stick with:

"Create new alias. Delete old alias"

Note that if you are hand-coding links to nodes within other nodes, the safest way in this case would be to only ever use the node/xxx for the href but then that causes problems with SEO since you really always want to use the same link throughout the site. One solution to this is the pathfilter module.

If the site is live and you are careful about creating your node titles, then you can use:

"Do nothing. Leave the old alias intact."

This is so that your node urls don't change even if you later change the node titles.

If you prefer that your urls *always* reflect the node title, then you should choose:

"Create a new alias. Redirect from old alias."

This will ensure that Google, etc. will find your new URL by getting redirected from the old one.

The only other option is:

"Create a new alias. Leave the existing alias functioning."

which is very dangerous since it could end up generating tons of "duplicate content" on your site. You should never have two URLs that show the same exact content. Redirecting from one URL to the other is fine though the best is to only have one URL for each page on the site.

It would be nice to have finer control over this behavior so that you could have it regenerate the alias for a particular node without having to change the default settings. Or perhaps, for unpublished nodes, it could continue to change the url since it's not live.

h) Transliterate prior to creating alias - I had trouble with this one previously but maybe it's working properly now. The idea is if you have special characters in your node title, that these will be replaced with a non-special character equivalent (e.g. n with tilda becomes just n). When I tried this out, it didn't work and ended up putting the node I tried it with in some weird state and generating errors. It could have been since I created the node first and then turned on this feature. Maybe I'll try to reproduce this later on for another article.

i) Reduce strings to letters and numbers from ASCII-96 - same idea as (h) but more restrictive

j) Strings to remove - add whatever makes sense to you

2) Punctuation settings - I use all the defaults

3) Other path settings (e.g. node path settings) - these should be set based on how you want your urls to look like on your site. If you want all blog posts to start with "blogs" and include the user id and title, you could use:


If you create a special content type and what that to be part of the url, you can do that as well, e.g.


Simply look at the "replacement patterns" and decide what pieces you want to use in your URLs for different content types. You can create your own replacement patterns using tokens.

It is good idea to try to think through your Drupal pathauto URL aliases settings before creating a bunch of content so you don't have to worry about the aliases changing due to changing your rules and patterns.

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web