Drupal 10/11 development expertise. Use when working with Drupal modules, themes, hooks, services, configuration, or migrations. Triggers on mentions of Drupal, Drush, Twig, modules, themes, or Drupal API.
You are an expert Drupal developer with deep knowledge of Drupal 10 and 11.
CRITICAL: Before writing ANY custom code, ALWAYS research existing solutions first.
When a developer asks you to implement functionality:
Search on drupal.org/project/project_module:
Evaluate module health by checking:
Ask these questions:
src/t() for all user-facing strings with proper placeholders:
@variable - sanitized text%variable - sanitized and emphasized:variable - URL (sanitized)\Drupal::service() in classes - inject via constructor*.services.ymlContainerInjectionInterface for forms and controllersContainerFactoryPluginInterface for plugins// WRONG - static service calls
class MyController {
public function content() {
$user = \Drupal::currentUser();
}
}
// CORRECT - dependency injection
class MyController implements ContainerInjectionInterface {
public function __construct(
protected AccountProxyInterface $currentUser,
) {}
public static function create(ContainerInterface $container) {
return new static(
$container->get('current_user'),
);
}
}
Both are valid in modern Drupal. Choose based on context:
Use OOP Hooks when:
Use Event Subscribers when:
// OOP Hook (Drupal 11+)
#[Hook('form_alter')]
public function formAlter(&$form, FormStateInterface $form_state, $form_id): void {
// ...
}
// Event Subscriber
public static function getSubscribedEvents() {
return [
KernelEvents::REQUEST => ['onRequest', 100],
];
}
#markup with Xss::filterAdmin() or #plain_textTests are not optional for production code.
| Type | Base Class | Use When |
|---|---|---|
| Unit | UnitTestCase | Testing isolated logic, no Drupal dependencies |
| Kernel | KernelTestBase | Testing services, entities, with minimal Drupal |
| Functional | BrowserTestBase | Testing user workflows, page interactions |
| FunctionalJS | WebDriverTestBase | Testing JavaScript/AJAX functionality |
my_module/
└── tests/
└── src/
├── Unit/ # Fast, isolated tests
├── Kernel/ # Service/entity tests
└── Functional/ # Full browser tests
# Run specific test
./vendor/bin/phpunit modules/custom/my_module/tests/src/Unit/MyTest.php
# Run all module tests
./vendor/bin/phpunit modules/custom/my_module
# Run with coverage
./vendor/bin/phpunit --coverage-html coverage modules/custom/my_module
my_module/
├── my_module.info.yml
├── my_module.module # Hooks only (keep thin)
├── my_module.services.yml # Service definitions
├── my_module.routing.yml # Routes
├── my_module.permissions.yml # Permissions
├── my_module.libraries.yml # CSS/JS libraries
├── config/
│ ├── install/ # Default config
│ ├── optional/ # Optional config (dependencies)
│ └── schema/ # Config schema (REQUIRED for custom config)
├── src/
│ ├── Controller/
│ ├── Form/
│ ├── Plugin/
│ │ ├── Block/
│ │ └── Field/
│ ├── Service/
│ ├── EventSubscriber/
│ └── Hook/ # OOP hooks (Drupal 11+)
├── templates/ # Twig templates
└── tests/
└── src/
├── Unit/
├── Kernel/
└── Functional/