On the subject of Extending Drupal 8

Apart from our mobile app development, we also do web development and maintenance. One of the sites that we maintain is the Cooler Crew web site, devoted to the St. Paul Winter Carnival Medallion Hunt, and similar treasure hunts in general (in the name of disclosure, the owner of this company is a long-time member of that group). We've been maintaining it for years, growing it from a massive collection of static pages, to something slightly database and template driven, to its current incarnation, built upon Drupal 6, and now Drupal 7. As with any site there's a rather large amount of code that goes into it. Some of the examples of code we've built includes the following:

  • One of the group members created holiday specific logos for the site, similar to what Google has done. While there is a way to have a site logo appear in a block, Drupal doesn't natively support dynamic logos, so we built a Holiday Logos module for the Drupal 7 site.
  • Periodically URL aliases on pages need to be changed. Since the page content remains the same it would be nice to track those changes and issue an appropriate redirect so that search engines and anyone who has bookmarks to a given page get sent to the new page, and the search engine history is retained. Not that all search engines do a good job of handling permanent redirects (Bing I'm looking at you). We created a simple alias manager module that implements hook_node_update to track previous aliases, and hook_url_inbound_alter to issue the redirects and keep track of when a given old alias was last used.
  • The site has a calendar which includes dates of ongoing treasure hunts around Minnesota and western Wisconsin, as well as other get-togethers. While its really not a huge deal to integrate the two types of events into a single calendar, we did it programatically, with a module to create a calendar_event content type, and one to create a calendar view that incorporates dates from both the calendar events and the treasure hunts, and also makes a "todays events" block available.
  • The site also archives things like newspaper articles about treasure hunt finders. If you peruse a newspaper's web site, you may notice that there's often a block present containing links to articles related to the one you're currently reading. We wanted to do the same linking these article archives to the appropriate treasure hunt, and do it automatically. Drupal provides a great system of tags, and we've created a module to leverage those tags to create a related content section on treasure hunt pages. It brings in a new field that can be added to any content type.
  • Finally, while the site could stand alone without any of the above functionality, it would be pointless to have without the information about the treasure hunts to which it is devoted. The information about a given treasure hunt includes dates, prize amounts, finders, rules, locations, how the treasure was concealed at that location, and most importantly the clues and what they meant. After a given hunt is over, and the meanings of the clues revealed, there's always a critic on them, so we added a fivestar field to the clues to allow people to give ratings to them.

So why are we talking about this now? As I mentioned earlier in this post, the site is built on Drupal 7. While Drupal 7 is certainly not outdated, we wanted to be able to migrate the site to Drupal 8, as it has been available for nearly two years at the time of this writing, and is the future direction of the code base. In addition there were a few shortcuts we took in developing some of the code for Drupal 7, and some functionality that wasn't completely implemented that we wanted to clean up. We figured it didn't make sense to do it in the existing code, so everything we're doing going forward is going to be for D8. There's one problem. Drupal 8 came with an enormous architecture change. Many hooks we'd relied on are no longer there. And what we've found along the way is that some of the things we wanted to do just aren't all that well documented. This blog series will set out to document some of the process we went through to create the modules necessary to migrate our existing custom site from Drupal 7 to Drupal 8.

We'll start with the Related Content module. It creates a new field type that can be embedded in any existing fieldable entity. It's already mostly completed, so bear with us as we "backport" the documentation. I say mostly completed, as its mostly functional, but there's also some room for improvement. For instance, the Drupal 7 version of the code is written so that when a node is updated with its tags, any nodes which either did point to the new node through their related content, or would have those links added are flagged as needing reindexing from the search module. This was so that the backlinks feature on a node was properly handled. Backlinks came out of Drupal 8, so implementing that wasn't a huge priority. The same thing was there with automated unit tests. We'll add that functionality back in, and it'll likely require some refactoring of queries, and how related tags are stored to make it happen. But the important thing right now is to get something usable for what we need and to show you how we did it.

After that, we'll work on the Treasure Hunt code, which will actually consist of multiple modules. The treasure hunt itself is a new content type on the node entity, and any given treasure hunt will have multiple clues. Like Drupal comments, we expect these clues to be their own fieldable entities. While we could have simply created a multiple-use field and attached it to a treasure hunt, we've gone the route of an entity for two reasons. First, we want to be able to add fields to it. Well, actually that's the only reason. When the Cooler Crew site started out all there was was the clues and their explanations dating back to 1952.  As the site added the current year's hunts, the previous maintainers, in addition to the official explanations provided by the newspaper running the hunt, would add in editorial comments. Sometimes, these editorial comments would be taken from various hunters' thoughts on what the clue might mean, especially with the benefit of hindsight after the treasure had been found. Making a static field would have made it difficult to add this sort of commentary to the clues after the fact, as well as made it difficult to add the fivestar clue ratings to the clues. We'll have to add dates and location, prize and finder information to the treasure hunt code, and we'll walk through that along the way.

The next piece of the treasure hunt puzzle will be implementing the particular treasure hunt type. The big show for the Cooler Crew is the annual hunt during the Winter Carnival. But there are a myriad of suburbs of the Twin Cities, as well as towns in greater Minnesota and Wisconsin with annual festivals that have some sort of treasure hunt attached to them. In addition several members of the group organize what they call mock hunts throughout the year as basically practice. It wouldn't make sense to lump all of these hunts together, so the Treasure Hunt data ends up being a taxonomy. In Drupal 7 this was hacked together with an artificial content type called a Treasure Hunt List Page, which was linked to a treasure hunt type. The list page was necessary because the main Winter Carnival hunt was historically divided into decades for smaller listings, and discussion of what happened hunt-wise in that decade. We haven't fully thought through how to go about doing that, but leveraging the taxonomy module has come to mind. Regardless, we anticipate creating an entity for Treasure Hunt types, and possibly a sub-entity for the list pages.

The current versions of the treasure hunt code also bring in Google Maps for geolocating where the treasure was hidden, so that a localized map can be attached to each individual treasure hunt, and a larger area map can be attached to the hunt type in general so that all previous locations for a given type of hunt can be displayed on a given page. The existing Treasure Hunt Mapping module provides this for us. But we also want to grow it for Drupal 8; currently all hunts share the same icon. We want to have the ability to give each hunt type its own icon. Municipal boundaries for Ramsey County and Saint Paul, MN are somewhat hard-coded. We'd like to be able to leverage some GIS system for that sort of thing in the future, possibly even getting down to the level of park boundaries.

Lastly in the treasure hunt category, we have a clue rating module, which depends on the fivestar and voting api modules. While at the least the voting api module has a development port for Drupal 8, fivestar does not. This isn't critical for the functionality of the site; we'll just have to hold on to the few votes we have on the site and migrate them when code is complete. That said, both projects are looking for new maintainers, so in order to implement this functionality we may end up completing the ports and seeking to maintain them going forward.

Once the treasure hunt module is complete, we'll look at the calendar-based modules we've created; the ones that create the Calendar Event content type, and then merge that with the Treasure Hunt to create a calendar view and a what's going on today block. There's not going to be a lot of code behind these, they're more configuration items than anything else.

The last hurdle to migration will be site theming. The current site uses a theme built on top of an old version of zen. Unfotunately, zen doesn't appear to be getting maintained in D8, so we'll start from scratch on that. Theming is not our forté, so like the current theme, we'll start with something new and mobile friendly, probably Bootstrap.

Following that, we'll work on the less necessary items: alias manager, and the holiday logos.

Oh yeah, and we'll make all of the code for these modules available as we go. There's not really anything proprietary about any of it and as much as we want to have these things documented for ourselves, we want to share this process with others who are doing site migrations as well!