
Creating Custom Modules in Drupal 11: A Beginner’s Guide
Drupal 11 is the latest iteration of one of the most powerful and flexible content management systems available today. If you’ve ever wondered how to extend Drupal’s functionality beyond the core and contributed modules, learning to create custom modules is essential. Creating Custom Modules in Drupal 11: A Beginner’s Guide will walk you through the necessary steps in a clear, beginner-friendly way while also keeping things professional and detailed.
This comprehensive guide explains the core concepts, highlights best practices, offers practical code examples, and introduces you to Drupal 11’s shift towards modern PHP standards. By the end, you’ll have the confidence to build your custom modules tailored to your project needs.
Understanding the Basics of Drupal 11 Module Development
Before diving into creating custom modules, it’s important to understand how Drupal’s module system works and why modules are vital to the flexibility of your site. Let’s break this down into approachable sections.
What Is a Drupal Module?
A Drupal module is a collection of functions and files that extend or alter Drupal’s core features. Modules can be:
- Core modules: shipped with Drupal by default.
- Contributed modules: developed and shared by the Drupal community.
- Custom modules: created specifically for your website’s unique requirements.
Creating custom modules lets you tailor Drupal to function exactly as you need.
Why You Should Create Custom Modules
Although Drupal has thousands of contributed modules, there are scenarios where none fully meet your requirements, such as:
- Integrating a bespoke third-party API.
- Adding custom forms or data processing workflows.
- Modifying content behavior in a fine-grained way.
Custom modules give you full control without bloating your site with unnecessary features from contributed modules.
Overview of Drupal 11 Module Structure
Drupal 11 embraces modern coding standards (PSR-4 for autoloading, Symfony components, PHP 8 features). The typical folder structure for a custom module is:
// my_module/
// ├── my_module.info.yml
// ├── my_module.module
// ├── src/
// │ ├── Controller/
// │ ├── Form/
// │ └── Plugin/
// └── my_module.routing.yml
Key files explained:
my_module.info.yml: Declares module metadata and dependencies.my_module.module: Contains hook implementations (optional in modern Drupal).src/: PHP classes for controllers, forms, and plugins using object-oriented code.my_module.routing.yml: Defines routes for controllers (pages, API endpoints).
Understanding this layout ensures you organize your custom module harmoniously with Drupal conventions.
Step-by-Step Guide to Creating Your First Drupal 11 Custom Module
Let’s move from theory to practice. Here is a straightforward process to create a simple “Hello World” module that renders a page with a friendly greeting.
Step 1: Create the Module Folder and Info File
Create a directory under web/modules/custom/hello_world. Then create a hello_world.info.yml file with the following content:
# hello_world.info.yml
name: 'Hello World'
type: module
description: 'A simple Drupal 11 custom module that displays a hello world page.'
core_version_requirement: '^11'
package: Custom
This metadata file registers your module with Drupal by providing its name, description, and core compatibility.
Step 2: Define a Route for Your Page
Create a hello_world.routing.yml file to define the URL path your module will respond to:
# hello_world.routing.yml
hello_world.content:
path: '/hello-world'
defaults:
_controller: '\Drupal\hello_world\Controller\HelloWorldController::content'
_title: 'Hello World'
requirements:
_permission: 'access content'
This configuration sets the URL /hello-world for your page, points to a controller method, and requires users to have the “access content” permission.
Step 3: Create the Controller Class
Inside the module folder, create the directory src/Controller. Add a PHP file named HelloWorldController.php With the following code:
<?php
namespace Drupal\hello_world\Controller;
use Drupal\Core\Controller\ControllerBase;
/**
* Returns a simple Hello World page.
*/
class HelloWorldController extends ControllerBase {
/**
* Builds the Hello World page content.
*
* @return array
* Render array with markup.
*/
public function content() {
return [
'#type' => 'markup',
'#markup' => $this->t('Hello, Drupal 11! Welcome to your first custom module.'),
];
}
}
This class extends Drupal’s base controller and returns a render array that Drupal will convert into HTML. The $this->t() function supports translations.
Step 4: Enable Your Module
Use Drupal’s administrative interface or the command line (via drush) to enable the module:
- Navigate to Extend in the Drupal admin and search for “Hello World,” then enable.
- Or via CLI:
drush en hello_world -y
Then, visit http://yourdrupalsite.local/hello-world to see your greeting.
Step 5: Understanding Permissions and Security
The route requires the “access content” permission, which is granted to authenticated and anonymous users by default, but configuring permissions correctly is critical for more complex modules.
Future modules may define custom permissions by adding hello_world.permissions.yml with entries like:
# hello_world.permissions.yml
administer hello world:
title: 'Administer Hello World module'
description: 'Allows users to configure the Hello World module'
You can then use these permissions on routes or hook implementations to control access securely.
Advanced Tips and Best Practices for Drupal 11 Custom Modules
As you expand your knowledge, it’s essential to keep your custom modules maintainable, performant, and aligned with Drupal standards. Here are some professional tips.
Use Dependency Injection Where Possible
Drupal 11 prefers dependency injection over using global Drupal static methods. This increases testability and modularity.
<?php
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
class ExampleController extends ControllerBase {
protected $loggerFactory;
public function __construct(LoggerChannelFactoryInterface $logger_factory) {
$this->loggerFactory = $logger_factory;
}
public static function create(ContainerInterface $container) {
return new static(
$container->get('logger.factory')
);
}
public function content() {
$this->loggerFactory->get('example')->info('Example page loaded.');
return ['#markup' => 'Check the logs'];
}
}
This approach improves code quality and aligns with Symfony and Drupal’s architecture.
Implement Drupal Hooks When Needed
Drupal hooks let your module react to system events, like form alterations or entity saves. Although plugins and events are increasingly used, hooks remain common.
Example: Add a hook to alter the site name displayed in the page header, placed in my_module.module:
<?php
/**
* Implements hook_preprocess_page().
*/
function my_module_preprocess_page(array &$variables) {
// Change the site name on all pages.
$variables['site_name'] = t('My Custom Site Name');
}
Hooks must be named exactly as modulename_hookname() and registered in your module.
Leverage Drupal Console and Devel Module for Faster Development
Use Drupal Console to generate boilerplate code instantly, such as controllers, forms, and plugins, enabling you to focus more on business logic rather than structure.
The Devel module assists you with debugging and performance profiling during development.
Follow Drupal Coding Standards
The Drupal community uses specific coding standards documented in the Drupal Coding Standards. Using automated code sniffers like phpcs enforces these and keeps your module consistent and maintainable.
Document Your Code
Detailed inline docblocks and README files improve the usability and longevity of your module, especially when collaborating or open-sourcing.
Real-World Example: Simple Contact Form Module in Drupal 11
To deepen your learning, let’s create a custom module named contact_form_example With a simple contact form that saves submissions to the database.
Step 1: Setup Module Basics
Define contact_form_example.info.yml:
name: 'Contact Form Example'
type: module
description: 'A simple contact form for Drupal 11.'
core_version_requirement: '^11'
package: Custom
dependencies:
- drupal:field
Step 2: Create the Form Class
We’ll create a form using Drupal’s Form API with object-oriented syntax:
<?php
namespace Drupal\contact_form_example\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Simple contact form example.
*/
class ContactForm extends FormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'contact_form_example_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['name'] = [
'#type' => 'textfield',
'#title' => $this->t('Your Name'),
'#required' => TRUE,
];
$form['email'] = [
'#type' => 'email',
'#title' => $this->t('Your Email'),
'#required' => TRUE,
];
$form['message'] = [
'#type' => 'textarea',
'#title' => $this->t('Message'),
'#required' => TRUE,
];
$form['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Send'),
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
\Drupal::messenger()->addMessage($this->t('Thank you %name, your message has been received.', ['%name' => $form_state->getValue('name')]));
// Here you could save the data or send an email.
}
}
Step 3: Define a Route to Display the Form
Create contact_form_example.routing.yml:
contact_form_example.form:
path: '/contact-form-example'
defaults:
_form: '\Drupal\contact_form_example\Form\ContactForm'
_title: 'Contact Us'
requirements:
_permission: 'access content'
Step 4: Enable and Test
Enable your module, visit/contact-form-example, fill out the form, and see the confirmation message.
This modular approach allows you to customize validation, integrate database APIs, or link with workflows as your project grows.
Additional Resources and Where to Learn More
Official Drupal Documentation
The most reliable and up-to-date resource is the official Drupal documentation at Drupal API Documentation. It contains detailed guides on module development, hooks, routing, and services.
Drupal Module Development Books and Tutorials
- Drupal 9 Module Development (also applicable for Drupal 11) – covers the fundamentals and modern practices.
- Online platforms such as Drupalize.Me or Lullabot offer video tutorials geared towards beginners and intermediate users.
Community Forums and Support
Join forums like Drupal.org forums or Drupal Slack channels where developers share experiences and help troubleshoot.
Let’s look into this as well
How to get a field value from a custom block?
Creating Custom Modules in Drupal 11: A Beginner’s Guide has introduced you to the fundamentals of custom module development, from understanding Drupal’s module structure to coding your first “Hello World” page and a simple contact form. As you continue, remember to focus on Drupal’s modern PHP patterns, best practices, and security considerations.
Mastering custom modules unlocks the true power of Drupal 11, empowering you to build tailored, maintainable web solutions. So don’t hesitate — start creating your own custom modules today, and watch your Drupal site flourish!
Ready to build your first module? Dive in, experiment, and transform your Drupal experience. Happy coding!

0 Comments