Facet's Drupal 7 Best Practices Checklist

I’m often surprised when our Drupal 7 best practices catch seasoned Drupal developers off-guard. We’ve worked with a good number of codebases over the years, and as with any optimization-driven developer, we always try to improve our processes and maximize efficiency. 

While our workflow is opinionated, our approach simplifies the knowledge transfer for onboarding new developers into projects. Without knowing the particulars of a project, our developers know how security updates are maintained, our standards for code review, and deployment best practices among other things. 

I want to share our experience with you so I'm publishing Facet’s Drupal 7 Assessment (with plans to release our Drupal 8/9 Assessment in the future!). We’ve gotten pretty good at assessing and adopting old code bases and applying our Drupal best practices, so I sincerely hope these checklists help you as a developer, Drupal agency owner, or in-house Drupal development team manager. Please, share your feedback and any additional items that you feel would improve the checklist!

Why Drupal 7?

We still maintain quite a few Drupal 7 sites, and while Drupal 8 is on the horizon for many, I believe Drupal 7 will be around for quite a few years. As Drupal 7 approaches end of life (EOL), more sites will need appropriate best practices and standards in place to simplify security and maintenance processes. 

What about Drupal 8 and Drupal 9?

We will be publishing our recommended best practices for Drupal 8/9 soon. Just as with Drupal 7, our best practices simplify the development and release management process—focusing on stability and bandwidth of developer output. 

Drupal 9 shouldn’t have significant changes to the best practices required versus Drupal 8. Once CMI 2’s roadmap lands a few deployment operations may be simplified, but otherwise it’s business as usual.

Who does this Drupal Checklist Help?

Drupal 7 Assessment for Agencies

While I’ve personally spent more than 10 years with Drupal and in this industry, I’ve never quite found resources like the one I’m sharing with you today. 

Most agencies and service providers in particular are extremely protective of their standard operating procedures. 

We all seem to protect how we deliver value to the world so that we can continue to earn a living.

But along the way, we solve the same problems over and over—often only slightly tweaking this process to reflect new experiences and challenges.

Here is to hoping that with this checklist in hand your agency can thrive and you face new challenges. 

Drupal 7 Assessment for Businesses

Not all sites require every checkbox in our Drupal 7 Assessment, but every checkbox in the assessment should apply to all websites.

Sometimes there is just a trade off in configuration, stability, scalability, or maintainability in your site. 

Knowing the difference between which items to implement or ignore comes from experience, so feel free to reach out if you have questions about your particular case.

In the end we have a number of benefits we tout to our customers:

  • Decreased costs. The time it takes to implement changes to the site are reduced, as deployments and testing are automated (or you approach that golden threshold of coverage). 
  • Faster turnaround times for work requests. We reduce context switching into a code base’s peculiarities—instead focusing on consistency for development standards. 
  • Increased stability. Our approach has the benefit of compounded experience across many different websites and code bases. This experience in turn lends itself to dependability. 
  • Key-man risk reduction. With multiple developers understanding best practices and conventions, we like to tell prospective customers that even if Facet were to one day blow up, many other Drupal developers would understand our best practices and be able to carry them forward. 

How to Navigate These Resources

Copy from one of the Google Doc Template or the Notion Checklist Template in order to start working with a live document. The rest of this page is, essentially, search engine food. If you want to browse the full list, please go right ahead and keep scrolling. 

Drupal 7 Assessment Google Doc Template

Facet Drupal 7 Assessment Template as a Google Doc 

Drupal 7 Assessment Notion Checklist Template

Facet Drupal 7 Assessment as Notion Checklist 

Drupal 7 Best Practices Checklist​

This is Facet's Drupal implementation best practices checklist and survey for onboarding new clients. It is not an exhaustive list, and it is fairly opinionated—but it's the best thing we have for mitigating risk and ensuring reduced total cost of maintenance when onboarding new clients.

Hosting Infrastructure

We assess the hosting infrastructure for each new client as they are onboarded in order to ensure they have an appropriately sized, supportable, performant, and scalable infrastructure.

From time-to-time, we may need to update the infrastructure hosting requirements for our clients depending on changing traffic, static file storage, or authenticated user traffic. Other variables may also apply.

Come back to this checklist as needed to demonstrate evolving needs to our clients.

  • Drupal-tuned hosting Provider?
    • When onboarding new clients who are already using Drupal, we ensure that our development workflow is streamlined and the total cost of ownership is reduced for ongoing updates, maintenance, and deployments.
    • We also don't present ourselves as infrastructure experts to our clients, and we depend on the expertise of these tuned-Drupal hosting providers to ensure ongoing infrastructure updates, performance optimizations, and other under-the-hood implementations are in place.
    • Pantheon
    • Platform.sh
    • Acquia
    • Amazee
    • Other?
  • File Storage

    Document the following information about the client's site in order to identify potential risks around supporting the site. We want to be aware of exceptional amounts of files to ensure the file storage infrastructure will continue to scale with the site's growth.

    • Size
    • Number of Files
    • File Types
    • File Tree/Structure
    • On-Server vs. 3rd Party Object Storage (s3)
  • CDN
    • Does the site use a CDN?
    • Is the CDN provided by the hosting provider?
    • Would a different/additional CDN provide additional performance?
    • What configuration is the CDN in? Origin Pull? Push?
  • Database
    • What database and version?
    • Is the database using an appropriate collation for the data?
    • Where is the database stored?
  • Caching
    • What caching information is already in place?
    • Is the authenticated user experience cached?
  • Search (Solr)
    • Is Solr currently set up on the site?
    • How is Solr configured?
    • Is Solr included in the platform service provider, self-hosted, or is it external PaaS?
  • Offsite Backups
    • What is the current offsite backup configuration?
    • Who has access to offsite backups?
    • In a step-by-step outline, how would the backups be restored?
  • HTTPS Secure Site
    • HSTS (Available on Pantheon)
  • Disaster Recovery / Continuity Plan
    • Does the site have a current disaster recovery plan?
    • Has the disaster recovery ever been tested?
    • What is the maximum allowable downtime for the site?

Telemetry

  • Production Performance Monitoring
    • NewRelic
    • DataDog
  • Uptime Monitor

Security

  • Drupal Version
  • Drupal Contrib Versions
  • PHP Version
    • If Low, Evaluate with PHPCompatibility for an upgrade to PHP 7.2+
      • Using our standard .lando.yml configuration, we can run PHPCompatibility with the following command from the Drupal web root.
      lando phpcscomp 
  • Library Versions (e.g. CKEditor)

Development Practices

  • Deployment Scripts / Cloud Hooks

    Assuming that we're on a Drupal-tuned hosting provider, we should have scripts in place to handle consistent deployment operations.

     

    Standard operations for Pantheon Quicksilver Platform are available on GitHub: https://github.com/pantheon-systems/quicksilver-examples.

     

    • On Deploy

      We deploy the following operations on each deploy:

      • Post to New Relic
      • Update Database
      • Revert Features / Config Import
      • Environment Switch
      • Clear Caches
      • Post to Slack
    • On Backfill / DB-import

      On backfill from the live environment, it is important to perform standard operations to clean up and reset the database for development.

      • Post to New Relic
      • Sanitize DB - User Emails, Credit Cards, PII
      • Enable Development Modules
      • Post to Slack
  • Programmatic Builds

    Programmatic builds are paramount to producing a consistently high-quality site experience. Many developers may touch a site over the course of its lifetime. The more we can distill a particular site's build process and maintenance processes into scripts, the more we can describe (via code) how the site operates and is maintained.

    • Appropriate usage of custom and contrib folders within sites/all/modules and sites/all/themes
      • We must separate the custom and contrib modules so that our build operations can delete contrib module and theme directories and download them fresh—ensuring an idempotent rebuild of the site from open source repositories.
    • Drush Make
      • ./build/site.make.yml - The website has a well-documented site.make.yml that allows us to idempotently rebuild the site over and over and get the same result.
        • When first building the site from a make file, it is important to successively rebuild it from the drush make command, modifying the site.make.yml file iteratively and ensuring the site artifact is generated to perfectly match the current site. That means running the make.sh should generate NO git diff.
        • We typically need to specify to the following granularity when building a site.make.yml for the first time.
          • Apply Drupal issue queue patches.
          • Perform a specific SHA1 commit checkout of a Drupal contrib module when the site was previously built with a -dev release. This commit represents the specific point in time that this site was built with the respective dev release.
          • Document the remaining git diff locally scoped to each Drupal contrib module, and save that diff as a custom patch to be applied during this build operation.
        • The end result of this iterative build process is a well-documented, fully patched Drupal site that can idempotently be rebuilt over and over.
      • ./build/make.sh - The website has a well-defined build process that details drush make, removal of Drupal contrib and library projects along with other build steps for the site's code scaffolding. Our goal is to ensure idempotent rebuilding for the site at any given time.
        • If there are any further customizations to be made to the build process besides our standard drush make from the site.make.yml detail them in this script.
        • After fully documenting the site's code scaffolding, we move on into applying updates to said code to bring Drupal core, contrib, and libraries up to current standards.
      • ./build/updatemake.sh - Updates the make.yml whenever we want to run updates. After successfully documenting the site's open source code and patches, run this updatemake.sh script to ensure the site is fully up to date.
        • If there are any customizations to the Drupal security update or library update process, make those customizations here.
        • For instance, sometimes repositories for old libraries are taken offline, and you must use another source.
    • Composer
      • Identify how composer is currently used to maintain the site's code.
      • If composer is used in combination with drush make ensure that the build steps for composer are also included in ./build/make.sh
    • Unused Modules
      • Are there modules that should be uninstalled?
      • To uninstall these modules, first make sure that the appropriate uninstall hooks are fired in the prod environment before removing these modules from the repository.
      • Typically, we would bundle our uninstall commands into our PROJECT_release_mgmt.install file, which controls the order and sequencing of updates as we deploy updates.
  • Git
    • .gitignore at root supports programmatic builds, log files, and folder structure without unnecessarily committing odd artifacts or hidden files.
    • .gitsubmodules remove all git submodules.
    • Check that there are no nested .git repositories other than the main root.
      • If we're deploying to Pantheon, we can't checkout any vendor projects with .git folders in the path as they aren't allowed to be committed.
      • When building from composer, we may need to ensure a custom script is executed to rename such .git folders and append an underscore → .git_
  • Drupal Site Audit Report
    • Pantheon provides this on the site dashboard as Status. This catches many things we also list here, but sometimes it's good to run the report and review it visually and highlight the items below which you know will need attention.
    • You can alternatively run this with drush sa
  • System Variables - settings.php

    Many of the following best practices are already pre-configured in our facet-d7-upstream example settings.php file: https://gitlab.com/facet-interactive/drupal-ops/facet-d7-upstream/-/blob/master/web/sites/default/settings.php

     

    When copying and setting up this file for the first time, or comparing the current settings.php against our best practices, consider the following checklist:

     

    • Environment Switches for System Variables
      • HTTP/HTTPS Redirects
        • Make sure we have appropriate redirection from HTTP to HTTPS browsing experience across the site.
      • Cache Settings
        • Cache setting for prod/live and test should be set in settings.php with an environment switch.
        • Lower environments should remain uncached to ensure speedy development.
      • Email API / SMTP Connection Credentials
      • Devel Config Defaults
        $conf['dev_timer'] = 1;
        $conf['devel_memory'] = 1;
        $conf['devel_query_sort'] = 1;
        $conf['devel_query_display'] = 0;
      • Reroute Email in non-live environments
        • Use the reroute_email module
    • Coding Standards
      • Configure Strict Reporting of PHP Notices in lower environments (NOT in live or test)
        // Turn on All Error Reporting
        error_reporting(E_ALL);
        ini_set('display_errors', TRUE);
        ini_set('display_startup_errors', TRUE);
        $conf['error_level'] = 2;
      • Check for count of similar logs in the watchdog table
        select message, count(*) as count
        from watchdog
        group by message
        order by count DESC;
      • Count PHP Notice Warnings in the Database
        select
               -- message,
               -- variables,
               substring_index(substring_index(substring_index(variables, ';',2),'"',-2),'"',1) as type,
               substring_index(substring_index(substring_index(variables, ';',4),'"',-2),'"',1) as message,
               substring_index(substring_index(substring_index(variables, ';',6),'"',-2),'"',1) as function,
               substring_index(substring_index(substring_index(variables, ';',8),'"',-2),'"',1) as file,
               substring_index(substring_index(variables, ';',10),':',-1) as line,
               count(*) as count
        from watchdog
        where variables like 'a:6:{s:5:\"%type\";s:6:\"Notice\"%'
        group by type, message, function, file;

         

  • Deployments
    • Release Management Module
      • The release management module is responsible for ensuring sequential database update commands are all logged. This allows us to ensure new modules get enabled, and then once enabled those modules respective .install files can manage their own independent updates.
      • When first installing the release management module, we want to ensure it starts at version 7000 when deployed to live for the first time.
      • After deploying the module to live, you may have to reset the version with the following command:
      drush ev "include 'includes/install.inc'; drupal_set_installed_schema_version('PROJECT_release_mgmt', '7000')"
      
    • Config Management
      • Features (D7)
        • Features are cleanly separated and not interdependent.
          • Features should be grouped based a single deployable site feature.
          • It is ideal if a module contains a single content type, or a set of content types that compose a single page, e.g. a homepage may have a slide content type, and some panels or other site building elements.
        • Features defining roles & permissions do not declare dependencies on modules.
          • Sometimes we group sitewide functionality, such as roles and permissions, into a single feature to make it easier to update permissions without creating the need to export multiple features when performing permissions updates.
      • Config Sync (D8)
        • Config Split (D8) - Dev/Test/Live
  • Caching Configuration

    Caching configuration is largely preconfigured for Pantheon with our facet-d7-upstream settings.php: https://gitlab.com/facet-interactive/drupal-ops/facet-d7-upstream/-/blob/master/web/sites/default/settings.php

     

    But if applying these changes manually, ensure the appropriate context of the following across multi-dev environments:

     

    • Page Caching
      • $conf['cache_lifetime'] = 0;
      • $[conf'page_compression'] = 0;
      • $conf['page_cache_maximum_age'] = 900;
    • Preprocess CSS / JS
      • $conf['preprocess_css'] = 1;
      • $conf['preprocess_js'] = 1;
      • AdvAgg Configured
        • Compress CSS
        • Compress JS
        • Move render-blocking JS to the footer
    • Asset Caching
      • JS, CSS, Images - Long cache lifetimes so CDN can continue to serve them.
        • Recommended a minimum of 1 week, e.g. 604800
    • Views
      • Views Query Caching
      • Views Render Caching
    • Layouts
      • Blocks Caching
      • Panels Caching
    • Entity Caching - entitycache
    • Object Caching - redis, memcache
    • Proxy Caching - Varnish, CDN
  • Custom Modules
    • Module Organization
      • Application-specific, or entity-specific?
      • Are implementations coupled to other modules, or are the modules clear and discrete?
    • Drupal Standards / Coder
    • Best Practices (found via search)
      • ['und'] → replace with → [LANGUAGE_NONE]
      • Use of eval()
      • SQL queries that run many lines instead of EFQ / DQ
  • Roles & Permissions
    • Admin uid=1 username and password is randomly hashed
    • Subadministrator is maximum granted level to Client Userse
    • Custom Permissions
      • Custom Permissions should be setup and used instead of role access checks in Views, menu hook callbacks, and custom modules.
      • Search for use of user_has_roles or $user->roles for any custom checks for sets of roles.
  • Drupal Modules
    • Gray List - It's easy to implement something that can be quite harmful to the system, meaning load, stability, maintainability. Review the following modules and the full extent of their configuration to ensure no damaging configurations are in place.
      • Rules
      • Computed Fields
    • Black List - Security concerns, abandoned projects, etc.
      • PHP Filter
    • Drupal Statistics
      • Issue Queue Count - Programmatically query the issue queue and count RTBC and other issues for 7.x or 8.x version as needed.
        • GROOM Patch Dev Work: Identify any issues which should be considered for applying a patch or our own development work.
          • Create a ticket in JIRA per-effort to resolve these items.
          • Group up the RTBC patches, but consider breaking them apart if the level of testing is going to significantly impact the size of the estimate (or total number of items to apply patches).
          • Any tickets which require additional development work / don't have a patch applied should be raised as a dev task / risk for consideration.

Database

  • Evaluate Cardinality of Indexes
  • Evaluate MySQL Slow Query Log for low-hanging fruit.

Local Development Workflow

Drupal 7

  • Development Modules
    • stage_file_proxy
    • reroute_email
    • environment
    • environment_status
  • Linter
    • Drupal Coder
    • PHPCS
    • .git/pre-commit/hook - to fire Drupal Coder PHPCS standards before each commit

      It's a bit extreme for some projects, but to enforce linting standard for each commit you can setup lando to copy the following script into .git/pre-commit/hook to prevent git commits unless the files in the commit pass linting:

      https://gist.github.com/skwashd/b353d59f460d5d77a2f7d99f5799fb96

    • GrumPHP?
    • PHPLint

Quality Assurance

Manual QA

  • Testing Plan
    • Are all critical functions clearly defined?
      • Can we transfer all testing items to a Google Sheet?
    • Who is responsible for testing?
      • What's their level of expertise?
      • Is testing their full-time or part-time responsibility?
    • If Facet is going to be responsible for testing, who is going to teach us about the website functionality / document the critical paths?
    • Who are the key power users? We can perhaps use these people as product champions and shorten the feedback loop during deployments.

Automated QA

Assess the current levels of automated testing available, and determine if investment into the following technologies is necessary to simplify our ongoing development, maintenance, and support.

  • Functional Testing (Interfaces)
    • Are there programmatic cron jobs or items which we'll need to rigorously define for testing?
  • Functional Testing
    • Is there sufficient complexity in the web application to justify automated tests? They require initial investment and upkeep.
    • Determine the sophistication of automated testing required. Should we use something like Behat or would a SaaS testing solution such as Ghost Inspector suffice?
    • What critical paths should be tested on each deploy as a smoke screen?
  • Visual Regression Testing
    • Is the site consistently undergoing front-end development?
  • Unit Testing
    • What code coverage do we currently have?
    • Is the code unit testable (e.g. OOP in D8) or is it largely hook-driven (D7).
    • Is there a clear need to refactor some code for cleaner separation of interfaces and testability?
    • Are there standard services which should be refactored into a Service Class? e.g. email, logging
  • Performance Testing / Load Testing
    • Are there any performance or load testing scripts in place to benchmark site performance?
    • Is the site’s revenue tied to page load speed and performance in a significant way?
    • Do we have to deal with a remarkable amount of traffic? Periodically or consistently?
    • Consider Recommending Blazemeter / Lokust for load testing
    • Consider Benchmarking the front-end page speed performance across the site
      • PageSpeed score should be >85

Release Management

  • Git Workflow
    • Determine if there is a defined git workflow that ties into current development and deployment infrastructure (CD)
    • If not defined, establish the branching, code review, and release management process.
  • Release Workflow

    Establish our best practices including defining the following for the project and communicating it with the client:

    • Release Manager, e.g. Facet Team Lead
    • Hotfix Approval Process (downtime, disaster recovery [DR] event, etc)
    • Release Signoff Process → See standard Facet JIRA Ticket for DEPLOY tickets.
  • Continuous Integration

    Assess and determine the current sophistication or level of need for implementing the following in a CI/CD pipeline:

    • Automated Tests
    • Programmatic Builds & Deploys

Drupal 7 TCO Optimization

Depending on the long-term goals of the Client, we may want to recommend incremental adoption of third-party systems to slowly decouple data from Drupal.

For example, consider approaches such as:

  • xautoload to implement OOP in Drupal 7
  • Data Lake / Data Warehouse Configuration for Reporting
  • Prepare for Drupal 7 LTS

Common Drupal Configurations

The following common Drupal configurations may not always be necessary, but certainly can improve the quality of various website archetypes.

Administrative Tools

  • Reroute Email in development environments. Make sure email cannot be sent from non-live environments by implementing the Reroute Email module.

Customer Support Tools

  • Implement Masquerade for easy login to end-customer accounts to provide better support to internal and external users.

Improve User Experience

  • Improve Email Deliverability with SMTP email sending. Implement SMTP, Mailsystem, and any third-party modules (e.g. Mandrill, Sendgrid) required for transactional email sending.

Maximize SEO

  • Metatag Configuration. Appropriate configuration of Content Types, Taxonomies, and Users, making sure that content that is not meant to be a landing page—such as Taxonomy Terms—are noindex,followed and other such foundational optimizations.
    • noindex low quality content / duplicate content
    • Metatag Views (metatag_views is included in metatag module)
  • Social Metatag Configuration. How do pages look on social platforms which are meant to be shared? Ensure that the appropriate image, header, and description are in the metatag markup for maximum impact on social platforms.
    • Open Graph Image Tags
    • Twitter Cards
  • URL Path Management. Appropriate configuration of Pathauto, Redirect, and Global Redirect modules.
    • Pathauto configurations follow a natural hierarchical pattern on the site (breadcrumb of the menu matches the URL structure).
  • Redirect Module Configuration Setup with Pathauto updates.
    • Redirects should be created when the path updates and the old path should be 301 redirected to the new path.
    • No redirects in .htaccess file.
  • XML Sitemap. Appropriate configuration of XML Sitemap for the publicly indexable site content.
    • Make sure it is submitted via Google and Bing Webmaster Tools.
    • Exclude content which is low value, or could adversely impact the site crawl allowance of the site.
  • Yoast SEO Module. Fuel constant improvement for Content Editors with immediate feedback on the node edit experience.