Skip to main content

Drupal 11.1 Introduces Hooks as Classes: History, Guide, and Tutorials

Drupal 11.1 brings a groundbreaking update that changes how hooks are implemented, offering developers the ability to define hooks as class methods using PHP attributes instead of the traditional function-based approach. This modernizes the codebase and embraces object-oriented programming (OOP) practices while maintaining backward compatibility with procedural code. In this blog post, we’ll explore the history of hooks in Drupal, the significance of this change, and walk through how to implement hooks using the new OOP approach, complete with code examples.

A Brief History of Hooks in Drupal

The concept of hooks has been integral to Drupal for almost 24 years. Introduced in the early 2000s, hooks allowed Drupal to remain flexible and extensible, giving developers a way to add custom behavior without directly modifying core code.

The first commit introducing hooks (#8d5b4e7b) in Drupal was made on December 23rd, 2000. Since then, hooks have been one of Drupal’s defining features, enabling modular code to work across various parts of the system.

Over the years, however, Drupal's reliance on procedural hooks made it increasingly harder to maintain, scale, and modernize the codebase. With Drupal 11.1, the platform embraces a more modern OOP approach, aligning Drupal with contemporary PHP practices.

Why the Change to Hooks as Class Methods?

While procedural function-based hooks are still supported in Drupal 11.1, the new object-oriented method brings several advantages:

  • Better code organization: By leveraging classes and methods, your hooks are grouped in a more logical structure.
  • Improved maintainability: OOP practices help reduce redundancy and make the codebase easier to maintain and extend.
  • Modern PHP standards: PHP attributes are part of the language's newer features, offering better performance and clarity.

This move also sets the stage for improved testability and decoupling, which is essential for large-scale Drupal applications.

Implementing Hooks as Class Methods in Drupal 11.1

Step 1: Define a Custom Module

For this example, we'll create a custom module named my_custom_module. You can create the module's structure as follows:

my_custom_module/
  ├── src/
  │   └── EventSubscriber/
  │       └── MyCustomSubscriber.php
  ├── my_custom_module.info.yml
  └── my_custom_module.module

Step 2: Define the Class with Hook Method

In Drupal 11.1, we can now define hooks directly within a class. Here's an example of a class that implements hook_theme() using PHP attributes.

namespace Drupal\my_custom_module\EventSubscriber;

use Drupal\Core\DependencyInjection\ContainerInterface;
use Drupal\Core\EventSubscriber\EventSubscriberInterface;
use Drupal\Core\Annotation\Hook;
use Drupal\Core\Theme\ThemeManagerInterface;

/**
 * Event subscriber to handle custom hooks.
 */
class MyCustomSubscriber implements EventSubscriberInterface {

  /**
   * Implements hook_theme() using PHP attributes.
   *
   * @Hook
   */
  public static function hookTheme(ThemeManagerInterface $theme_manager) {
    return [
      'my_custom_template' => [
        'variables' => ['my_variable'],
      ],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    // Return an array of events and their handlers
    $events = [];
    return $events;
  }
}

Here’s what happens in the code above:

  • The MyCustomSubscriber class uses a PHP attribute @Hook to indicate that the method hookTheme() should be treated as a hook.
  • This approach eliminates the need for function-based hooks like function my_custom_module_theme().
  • The hook is defined as a method within the class, providing better structure and encapsulation.

Step 3: Enable the Module

You can enable the module using Drush or the Drupal admin interface:

drush en my_custom_module

After enabling the module, Drupal will recognize the hook, and you can use it just as you would with traditional hooks.

Example 2: Using Hooks with Dependency Injection

In Drupal 11.1, it’s now possible to use dependency injection within hook implementations. Here's an example of a class-based hook_form_alter() implementation with dependency injection.

namespace Drupal\my_custom_module\Form;

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\DependencyInjection\ContainerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormBuilderInterface;

/**
 * Class that implements hook_form_alter().
 */
class MyCustomFormAlter {

  /**
   * @Hook
   */
  public function alterForm(array &$form, FormStateInterface $form_state, $form_id) {
    if ($form_id === 'user_profile_form') {
      // Alter the user profile form.
      $form['#submit'][] = [$this, 'myCustomSubmitHandler'];
    }
  }

  /**
   * Custom submit handler for the form.
   */
  public function myCustomSubmitHandler(array &$form, FormStateInterface $form_state) {
    // Handle form submission.
  }
}

In this example:

  • alterForm() is now a method in a class that can be hooked into Drupal’s form system.
  • The class method is annotated with @Hook to mark it as a hook.
  • The FormStateInterface and FormBuilderInterface dependencies can be injected into the class, allowing for more flexible and testable code.

Benefits of Using Hooks as Classes

  • Encapsulation: Grouping hooks within a class provides better structure to your code, making it easier to understand and maintain.
  • Better testability: With OOP, you can better isolate and test each piece of functionality.
  • Code reuse: Classes allow you to reuse methods across different parts of your application without duplication.
  • Consistency: Following OOP principles brings consistency to your Drupal development process.

Conclusion

Drupal 11.1’s introduction of hooks as class methods with PHP attributes represents a major step toward modernizing the Drupal ecosystem. By adopting this object-oriented approach, developers can write cleaner, more maintainable, and scalable code while still maintaining support for older procedural hook implementations. Whether you're building a new project or updating an existing one, this change provides a powerful new way to work with Drupal hooks.

In this post, we’ve provided both the history and the practical aspects of using hooks as classes, along with code examples to help you get started with this new feature. Start exploring the new Drupal 11.1 features today and take advantage of this exciting update!

Tags

Recent Blogs