Taking on 100% of the build-out of a modern Drupal site is something that I don’t get to do very often. At my regular job, tasks such as backend, site-building, sys admin, SEO, and front-end are split up among specialized developers. Though it's a large amount of work, I get to flex some underused muscles when I create the whole site myself.
Last week, I launched the new version of my buddy’s website in Drupal 9, The Masters Lawn Care (aka TMLC). While this website sees magnitudes less traffic than the vast majority of Drupal sites on the web, I still consider it to be rather ambitious.
Below, I’ll walk you through some of the cool features, techniques, modules, and plugins that I’ve used. I’ll talk about how I’m contributing some of the code back to the Drupal community!
History of the Masters Lawn Care website
Mid-2000’s: table layouts and ASP
Waaaay back in the mid 2000’s, I used to offer websites in exchange for contracting work in the “barter” section of Craigslist. Rusty (the owner of TMLC) reached out to me, and he traded an irrigation system and lawn care in exchange for this beauty of a website (courtesy of archive.org), which was built with a mix of static HTML, table layouts, and some classic ASP scripting. Joking aside, this website was better than all of his competitors, and helped his business rapidly grow.
Note that I have not mowed my lawn since 2007 because of this agreement!
2012: Moving to Drupal
The next version of the TMLC website came along in 2012. This was to be the first ever Drupal 7 site that I built, and I remember borrowing heavily from the Vollaci website design because of Ben Finklea’s awesome DrupalCon San Francisco session on conversion rate optimization.
Drupal turned out to be a perfect fit. We had content types for services, blogs, etc. Fields had relationships to taxonomy tags, and multiple content editors with custom permissions, etc. And the Webform module did a lot of heavy lifting while collecting leads. When Rusty would occasionally ask for changes to content types or views, or integrations with other software, Drupal would easily accommodate!
Around 2018, we decided to refresh the design. I designed and implemented a theme with a background video, integrated quote form, and redesigned the site so it was fully responsive (the previous site had an m.* domain). I elected to keep the site on Drupal 7, as there really wasn’t any need to upgrade, and Drupal 7 was still going strong.
TMLC’s Drupal 9 website features / improvements
Drupal 7 served for over ten years! However, with the looming Drupal 7 end-of-life, and changing business requirements, it was obvious that it was time to upgrade. In addition to upgrading Drupal, I wanted to re-write the theme to be more modular, accessible, and performant.
Improved accessibility
Since the previous version of the website, I’ve been fortunate enough to greatly improve my accessibility knowledge through lots of work on Drupal core. I wanted to take advantage of this to make the new site highly accessible to those who need it.
Primary navigation
The primary navigation system borrows heavily from the work that I did in Drupal’s default Olivero theme. The secondary menus are fully keyboard accessible, as well as accessible on touch devices (which sometimes is harder than you’d think). The mobile menu contains a focus trap to ensure that focus cannot shift to covered up elements, and focus states are extremely apparent.
Background video
While autoplaying background videos can frequently be problematic, I worked very hard to ensure that the solution implemented was accessible as possible.
The background video autoplay setting respects the user’s prefers-reduced-motion
media query setting (which is controlled by a setting within the operating system). In addition, a play/pause button exists which will save the autoplay setting to your browser's localStorage
, which will ensure the setting is saved for the user in the future. I also attached a click
event to the video element itself that triggers a button click. This reproduces YouTube functionality where a user can click on the video to play/pause.
Estimate form
The estimate form that appears on most pages is deceptively complicated. There is a need to save vertical space, while at the same time displaying multiple form fields. To accommodate this, I wrote some custom JavaScript that detects if 1) the form field has focus, or 2) the form field has data. If it does, it moves the <label>
element above the field and applies styling to it. This allows the height of the form to be minimal, while still allowing for excellent usability and accessibility of the form elements.
I also engineered a custom multi select loosely based on Adrian Roselli’s Under-Engineered Multi-Selects component. This component uses a <button>
element to toggle the appearance of a <fieldset>
, which in turn contains checkboxes for various services the customer is interested in. Natively, this could be accomplished with a <select multiple>
element, but the usability of this on desktop browsers is poor.
Improved performance
The Drupal 9 version of the website has significantly improved performance. While no specific technique is used to “make it fast”, the gain was achieved with a combination of best practices and testing.
- We’re hosting the website on Pantheon, which includes the Fastly content delivery network.
- We’re implementing the WebP image format, which drastically reduces image size.
- Minimal use of JavaScript and CSS without bloated frameworks.
- Use of system fonts.
- Lazy-loading of images, and ensuring that above-the-fold images are not lazy-loaded.
In addition to the best practices above, I also did extensive testing with WebPageTest and PageSpeed Insights to make sure I wasn’t neglecting anything.
Note there’s still some room for improvement here. Still to do are implementing responsive images for heroes, and using WebM format for the video files.
New Views pager and slideshow
Two user experience wins are an improved “load more” pager, and an improved “lightbox” image gallery experience.
Pager load More
The image gallery and blog views utilize a custom pager solution. It’s heavily JavaScript based, and it works by modifying the DOM to add the “Load more” button, and then tracks the current page when the button is clicked. This means that if you navigate back to the URL, it will load all the previous loaded content (this is something that other solutions don’t do)!
I’m working on creating a contrib module for this (see https://www.drupal.org/project/pager_load_more). The JavaScript is working well, but it still needs some backend work if anyone wants to join in the fun 😀.
Image slideshow
On the photos page, we needed to implement a lightbox plugin. In Drupal 7, we had Colorbox, but I found it slow, and partially bloated.
For the new functionality, I created a custom implementation of the Tobii library. I selected this library because
- No JavaScript dependencies such as jQuery
- It passed all the accessibility tests I could throw at it including focus trap, arrow keys, ESC key, etc.
- It was fast and intuitive
In the future, I’d love to create a module to implement a Views plugin for this. It’s a great library, and I think lots of people could benefit from it.
Location handling
TMLC recently opened up their second location, so we have a need to manage that within the new website. To do so, I set up custom logic to change data on the server (as opposed to using JavaScript) for SEO reasons.
- Content types can be associated with a location (via a taxonomy term)
- If the user navigates to a page where the taxonomy term is set, we set custom variables that include phone numbers, etc.
- We then set a location cookie using JavaScript
- The cookie is read by PHP and the variable is set.
- Drupal’s caching system is made aware by setting a cache context for this cookie.
- HTTP headers are then output with this cache tag so the Fastly CDN can cache each version of the page.
Super thank you to Connerton for helping me with this!
Improved editorial abilities
Another driving factor behind the upgrade is to give editors the ability to create new landing pages. Within the Drupal 7 site I was frequently asked to create custom CTAs, blocks, etc and add them to specific pages. With Drupal 9’s Layout Builder capabilities, that can now be done through the admin UI.
Out of the box, Layout Builder is still a bit half-baked, with some significant usability issues. To work around several of these, I’m using Layout Builder Styles, Inline Block Title Automatic, Entity Browser Block, Block List Override, and the Layout Builder Direct Add modules.
In addition, I created some custom styles to fix the Layout Builder form actions to the bottom of the viewport.
Next steps and Drupal 10
It feels good to launch a new website that you’re proud of! However, there’s still a bit of work to be done before it goes into “maintenance”. I have plans to do continued UX improvements to the Layout Builder implementation. I’d also like to create custom tokens when setting the user’s locations, and maybe even automatically set the user’s location via IP geolocation.
Eventually, this site will be upgraded to Drupal 10. Thankfully, because of Drupal’s commitment to Easy Upgrades Forever, future upgrades will be much easier!
In the meantime, if you live in the Gainesville, Jacksonville, St Augustine, or Nocatee areas, and you're looking for lawncare service, check out the new website at https://themasterslawncare.com.
Hey you! Leave a comment!4
Seriously... I really like it when people let me know their thoughts and that they've read this.
Keep up the good work. You just might be getting the hang of this Drupal stuff.
Great write-up Mike. The Pager Load and location handling aspects were particularly interesting...and inspirational.
Thanks for sharing. A great write-up.
Mike - you rock. I dont know what half the stuff above means - other than you sure can make an awesome website full of all the functionality we can think of. Thank you for all the hard work!!