Drupal Code Review
You are reviewing Drupal code against this team's established coding standards. The goal is to catch issues before they reach production — security holes, stale cache metadata, outdated PHP patterns, and architectural problems are all fair game.
References library: references/
Start by reading README.md in that directory for a quick map, then read only the reference files relevant to what you're reviewing. Don't load all 15 files — be surgical.
Step 1: Understand what to review
If $ARGUMENTS contains file paths, read those files. If the user pasted code inline, work with that. If neither, ask: "What file or directory should I review?"
Scan the code quickly to identify which categories apply before loading reference files.
Step 2: Load relevant references
| Code contains... |
Read this reference file |
*.info.yml, module structure |
01-module-architecture.md |
Services, *.services.yml, create() factory |
02-services-dependency-injection.md |
#[Block], #[FieldType], #[QueueWorker], plugin classes |
03-plugins.md |
| Entity classes, base field definitions |
04-entities.md |
*.routing.yml, controllers, AccessResult |
05-routing-access.md |
FormBase, ConfigFormBase, #ajax |
06-forms.md |
$this->database->, hook_schema, hook_update_N |
07-database.md |
ConfigFactoryInterface, StateInterface, TempStoreFactory |
08-configuration.md |
#cache, render arrays, CacheableMetadata |
09-caching.md |
| User input, permissions, CSRF tokens, file uploads |
10-security.md |
Twig templates, *.theme, *.libraries.yml, SDC |
11-theming.md |
Test classes, UnitTestCase, KernelTestBase |
12-testing.md |
DrushCommands, composer.json, drush.services.yml |
13-deployment.md |
#[Hook], *.module hook functions, src/Hook/ |
14-oop-hooks.md |
Always read 15-modern-php.md when reviewing any PHP code — PHP 8.4/8.5 patterns apply everywhere.
Always read 10-security.md when there is user input, file handling, or permission checks.
Step 3: Produce the review
Structure your output exactly like this:
Drupal Code Review: [filename or module name]
Critical Issues
Security vulnerabilities, broken access control, data loss risks. Must fix before merge.
Standards Violations
Deviations from Drupal 11 / PHP 8.5 coding standards. Should fix.
Recommendations
Improvements that follow best practices but aren't blocking.
Confirmed Good Practices
Patterns done correctly — acknowledge briefly so the developer knows what to keep.
For each finding:
- Cite the reference (e.g., "→
10-security.md: Never concatenate user input into SQL")
- Show the problematic snippet
- Show a corrected version
If there are no issues in a section, write "None found." — don't omit the section.
High-value checks to run on every review
These catch the most common Drupal 11 mistakes — worth checking even before reading the full reference files:
PHP / OOP patterns
- No
\Drupal:: static calls inside service classes (use constructor injection instead — statics break testability and the service container)
- PHP native attributes used, not Doctrine annotations:
#[Block(...)] not /** @Block(...) */
- Constructor property promotion:
public function __construct(private readonly FooService $foo) — the verbose property-then-assign pattern is outdated
- All parameters, return types, and properties have type declarations
Hooks
- Hooks implemented as
#[Hook] classes in src/Hook/ (Drupal 11.1+), not as procedural functions in .module
hooks_converted: true set in *.info.yml if all hooks are OOP
Caching
- Every render array has
#cache with tags and contexts — missing cache metadata causes stale content for users
- Cache context is
user.roles not user for role-based variations (the user context disables page caching)
Security
- No user input concatenated into SQL strings (use DB API placeholders)
- No
|raw in Twig on user-supplied content (Twig auto-escapes; |raw bypasses it entirely)
- Routes have explicit
requirements: keys
Config
- Config schemas defined in
config/schema/ for every key the module introduces
1---2name: drupal-review3description: Review Drupal code against team standards for Drupal 11, PHP 8.4/8.5, and modern best practices. Use this skill whenever someone asks to review a Drupal module, check a PR, audit Drupal architecture, or validate that code follows standards.4---56# Drupal Code Review78You are reviewing Drupal code against this team's established coding standards. The goal is to catch issues before they reach production — security holes, stale cache metadata, outdated PHP patterns, and architectural problems are all fair game.910**References library:** `references/`1112Start by reading `README.md` in that directory for a quick map, then read only the reference files relevant to what you're reviewing. Don't load all 15 files — be surgical.1314## Step 1: Understand what to review1516If `$ARGUMENTS` contains file paths, read those files. If the user pasted code inline, work with that. If neither, ask: "What file or directory should I review?"1718Scan the code quickly to identify which categories apply before loading reference files.1920## Step 2: Load relevant references2122| Code contains... | Read this reference file |23|---|---|24| `*.info.yml`, module structure | `01-module-architecture.md` |25| Services, `*.services.yml`, `create()` factory | `02-services-dependency-injection.md` |26| `#[Block]`, `#[FieldType]`, `#[QueueWorker]`, plugin classes | `03-plugins.md` |27| Entity classes, base field definitions | `04-entities.md` |28| `*.routing.yml`, controllers, `AccessResult` | `05-routing-access.md` |29| `FormBase`, `ConfigFormBase`, `#ajax` | `06-forms.md` |30| `$this->database->`, `hook_schema`, `hook_update_N` | `07-database.md` |31| `ConfigFactoryInterface`, `StateInterface`, `TempStoreFactory` | `08-configuration.md` |32| `#cache`, render arrays, `CacheableMetadata` | `09-caching.md` |33| User input, permissions, CSRF tokens, file uploads | `10-security.md` |34| Twig templates, `*.theme`, `*.libraries.yml`, SDC | `11-theming.md` |35| Test classes, `UnitTestCase`, `KernelTestBase` | `12-testing.md` |36| `DrushCommands`, `composer.json`, `drush.services.yml` | `13-deployment.md` |37| `#[Hook]`, `*.module` hook functions, `src/Hook/` | `14-oop-hooks.md` |3839Always read `15-modern-php.md` when reviewing any PHP code — PHP 8.4/8.5 patterns apply everywhere.40Always read `10-security.md` when there is user input, file handling, or permission checks.4142## Step 3: Produce the review4344Structure your output exactly like this:4546---47## Drupal Code Review: `[filename or module name]`4849### Critical Issues50*Security vulnerabilities, broken access control, data loss risks. Must fix before merge.*5152### Standards Violations53*Deviations from Drupal 11 / PHP 8.5 coding standards. Should fix.*5455### Recommendations56*Improvements that follow best practices but aren't blocking.*5758### Confirmed Good Practices59*Patterns done correctly — acknowledge briefly so the developer knows what to keep.*6061---6263For each finding:64- Cite the reference (e.g., "→ `10-security.md`: Never concatenate user input into SQL")65- Show the problematic snippet66- Show a corrected version6768If there are no issues in a section, write "None found." — don't omit the section.6970## High-value checks to run on every review7172These catch the most common Drupal 11 mistakes — worth checking even before reading the full reference files:7374**PHP / OOP patterns**75- No `\Drupal::` static calls inside service classes (use constructor injection instead — statics break testability and the service container)76- PHP native attributes used, not Doctrine annotations: `#[Block(...)]` not `/** @Block(...) */`77- Constructor property promotion: `public function __construct(private readonly FooService $foo)` — the verbose property-then-assign pattern is outdated78- All parameters, return types, and properties have type declarations7980**Hooks**81- Hooks implemented as `#[Hook]` classes in `src/Hook/` (Drupal 11.1+), not as procedural functions in `.module`82- `hooks_converted: true` set in `*.info.yml` if all hooks are OOP8384**Caching**85- Every render array has `#cache` with `tags` and `contexts` — missing cache metadata causes stale content for users86- Cache context is `user.roles` not `user` for role-based variations (the `user` context disables page caching)8788**Security**89- No user input concatenated into SQL strings (use DB API placeholders)90- No `|raw` in Twig on user-supplied content (Twig auto-escapes; `|raw` bypasses it entirely)91- Routes have explicit `requirements:` keys9293**Config**94- Config schemas defined in `config/schema/` for every key the module introduces