Writing clean and maintainable code is essential for the long-term success of any Drupal project. Drupal is a powerful and flexible content management system, but to fully leverage its potential and ensure that your site remains easy to maintain and scale, it's crucial to follow best practices when writing code. This includes adhering to Drupal coding standards, embracing object-oriented programming (OOP) principles, and creating custom modules that follow best practices while avoiding hacks that bypass core functionality.
In this blog post, we’ll explore the following key aspects of writing clean and maintainable code in Drupal:
- Coding Standards: Why it’s important to follow Drupal’s coding standards for PHP, JavaScript, CSS, and Twig, and how these standards improve the quality and consistency of your code.
- Object-Oriented Programming (OOP): How to effectively use OOP principles when developing custom modules for Drupal 8, 9, and beyond, and why OOP is a key component of maintainable code.
- Custom Modules: When and how to write custom modules, with a focus on following naming conventions, avoiding hacks, and ensuring that your modules are scalable and maintainable.
By the end of this post, you’ll have a clear understanding of how to write code that’s not only functional but also clean, scalable, and easy to maintain, ensuring that your Drupal site remains sustainable in the long term.
Coding Standards: Follow Drupal’s Standards for PHP, JavaScript, CSS, and Twig
Drupal has a set of well-defined coding standards that developers are expected to follow. These standards ensure that code is consistent, readable, and easy to maintain across the entire Drupal ecosystem. Whether you’re writing PHP, JavaScript, CSS, or Twig templates, adhering to these standards is essential for building a clean, maintainable codebase.
Why Coding Standards Matter
- Consistency: When code follows a consistent format, it becomes easier to read and understand. This is particularly important when working in teams, where multiple developers may contribute to the same codebase.
- Maintainability: Code that follows Drupal’s standards is easier to maintain and debug. It also makes it easier for new developers to understand and contribute to the project.
- Community Contribution: Drupal is an open-source platform, and if you plan to contribute code to the community (whether it’s a module, theme, or patch), your code must adhere to Drupal’s coding standards.
Key Drupal Coding Standards
PHP Coding Standards
Drupal has strict guidelines for writing PHP code. These guidelines cover everything from indentation and spacing to how variables and functions should be named. Here are some key aspects of Drupal’s PHP coding standards:
- Indentation: Use two spaces for indentation, not tabs.
- Naming Conventions: Use snake_case for variable and function names, and PascalCase for class names.
- Comments: Use proper comments to explain your code. Use
/** */
for function and class docblocks, and//
for inline comments.
Example: PHP Code Following Drupal Standards
/**
* Implements hook_menu().
*/
function mymodule_menu() {
$items['mymodule/page'] = [
'title' => 'My Custom Page',
'page callback' => 'mymodule_page',
'access callback' => TRUE,
];
return $items;
}
/**
* Page callback for mymodule/page.
*/
function mymodule_page() {
return [
'#markup' => t('Welcome to my custom page!'),
];
}
In this example, the code follows Drupal’s PHP coding standards by using proper indentation, naming conventions, and comments.
JavaScript Coding Standards
Drupal’s JavaScript coding standards are similar to the PHP standards in terms of indentation and naming conventions. Additionally, Drupal encourages the use of modern JavaScript techniques, such as ES6 syntax, but maintains compatibility with older browsers.
- Indentation: Use two spaces for indentation.
- Variable Declarations: Use
let
orconst
instead ofvar
. - Avoid Global Variables: Always scope your variables properly to avoid polluting the global namespace.
Example: JavaScript Code Following Drupal Standards
(function ($, Drupal) {
'use strict';
Drupal.behaviors.mymoduleBehavior = {
attach: function (context, settings) {
$('body', context).once('mymodule').each(function () {
console.log('My custom behavior attached.');
});
}
};
})(jQuery, Drupal);
This example uses Drupal’s JavaScript standards, including the use of once()
to ensure that the behavior is only attached once, and the closure to avoid polluting the global namespace.
CSS Coding Standards
Drupal’s CSS coding standards ensure that stylesheets are organized, consistent, and easy to maintain. Some key principles include:
- BEM Naming Conventions: Use BEM (Block Element Modifier) conventions for class names to make CSS more modular and maintainable.
- Avoid !important: Avoid using
!important
in your styles, as it can make your CSS difficult to override and maintain.
Twig Coding Standards
Since Drupal 8, Twig has been the templating engine for Drupal themes. Twig coding standards focus on keeping templates clean, readable, and easy to override:
- Indentation: Use two spaces for indentation.
- Logic in PHP, Not Twig: Keep logic out of Twig templates whenever possible. Use PHP to process data and pass it to the templates.
- Filters and Escaping: Always use the
|escape
filter when outputting variables to prevent XSS attacks.
Object-Oriented Programming (OOP): Utilize OOP Principles in Custom Modules
With the advent of Drupal 8 and 9, Drupal has fully embraced object-oriented programming (OOP). OOP allows for more modular, reusable, and maintainable code by organizing functionality into classes and objects.
Benefits of Using OOP in Drupal
- Modularity: OOP promotes the reuse of code by organizing functionality into classes and objects. This modularity makes it easier to maintain and extend your code.
- Encapsulation: OOP allows you to encapsulate functionality, keeping the implementation details hidden and providing a clear interface for interacting with objects. This reduces the risk of accidental changes to the core logic of your application.
- Extensibility: With OOP, you can easily extend or override existing functionality by using inheritance and interfaces, rather than duplicating code.
Key OOP Concepts to Use in Drupal
Classes and Objects
In OOP, code is organized into classes that define the behavior and properties of objects. In Drupal, you’ll often create classes to define custom services, plugins, or controllers.
Example: Defining a Custom Service in Drupal
namespace Drupal\mymodule;
use Drupal\Core\Config\ConfigFactoryInterface;
class MyCustomService {
protected $configFactory;
public function __construct(ConfigFactoryInterface $config_factory) {
$this->configFactory = $config_factory;
}
public function getCustomConfig() {
return $this->configFactory->get('mymodule.settings');
}
}
In this example, a custom service is defined using a class. The service retrieves configuration settings using dependency injection.
Interfaces and Inheritance
Drupal’s OOP architecture allows for interfaces and inheritance, which are powerful tools for extending and customizing functionality.
- Interfaces define a contract that classes must follow, making it easier to swap out implementations without affecting the rest of the code.
- Inheritance allows you to create base classes with common functionality and extend those classes to provide specific implementations.
Example: Creating a Custom Plugin with an Interface
namespace Drupal\mymodule\Plugin\Block;
use Drupal\Core\Block\BlockBase;
/**
* Provides a custom block.
*
* @Block(
* id = "custom_block",
* admin_label = @Translation("Custom block"),
* )
*/
class CustomBlock extends BlockBase {
/**
* {@inheritdoc}
*/
public function build() {
return [
'#markup' => $this->t('This is a custom block!'),
];
}
}
In this example, we create a custom block plugin that extends BlockBase
, which is part of Drupal’s Plugin API.
Custom Modules: Write Custom Modules When Necessary, But Follow Best Practices
Sometimes, contributed modules won’t meet the specific needs of your project, and you’ll need to write custom modules. When writing custom modules, it’s important to follow Drupal’s naming conventions, avoid hacks that bypass core functionality, and ensure that your modules are easy to maintain and extend.
Best Practices for Writing Custom Modules
- Follow Naming Conventions: Custom modules should have a machine name that follows Drupal’s naming conventions. For example, a module named "My Custom Module" should have a machine name of
mymodule
. - Use Hooks and Events, Not Hacks: Drupal provides a robust system of hooks and events that allow you to alter the behavior of core functionality without modifying the core code. Always use hooks or events to extend functionality rather than hacking the core code directly.
- Structure Your Code Properly: Organize your custom module’s code into a clear and logical structure. Use the following directory structure:
/src/
: Contains PHP classes (e.g., controllers, plugins, services)./templates/
: Contains Twig templates./config/
: Contains configuration files./tests/
: Contains automated tests.
Example: Writing a Custom Module
Here’s a basic example of how to create a custom module in Drupal:
- Create the Module Directory: Create a new directory in
modules/custom/
namedmymodule
. - Define the Module’s Info File: Create a
mymodule.info.yml
file:
name: 'My Custom Module'
type: module
description: 'Provides custom functionality for my site.'
core_version_requirement: ^8 || ^9
package: Custom
dependencies:
- drupal:node
- Write a Hook to Alter a Node’s Behavior: Create a
mymodule.module
file:
/**
* Implements hook_node_view_alter().
*/
function mymodule_node_view_alter(array &$build, \Drupal\node\NodeInterface $node) {
if ($node->getType() == 'article') {
$build['#suffix'] = '<p>Custom text added to all articles.</p>';
}
}
In this example, the hook_node_view_alter()
function is used to alter the rendering of nodes of type article
, adding custom text to the output.
Conclusion
Writing clean and maintainable code in Drupal is essential for creating scalable, secure, and long-lasting websites. By adhering to Drupal’s coding standards, embracing object-oriented programming, and following best practices for custom module development, you ensure that your Drupal project remains manageable and adaptable as it grows.
Following the Drupal way means more than just writing functional code—it means writing code that’s consistent, readable, and maintainable. Whether you’re working on a small site or a large enterprise project, these best practices will help you create code that stands the test of time and keeps your site running smoothly for years to come.
So, remember: write clean, follow Drupal standards, and always aim for maintainability.