Install
$ agentstack add skill-edutrul-drupal-ai-drupal-hooks ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Drupal Hooks (Drupal 11)
OOP Hooks (Preferred)
| | | |---|---| | Location | src/Hook/MyModuleHooks.php | | Namespace | Drupal\my_module\Hook | | Auto-registered | Drupal 11.1+ (no services.yml needed) | | DI support | Constructor injection | | Testable | Yes — instantiate directly, inject mocks |
Example (Best Practice)
t().
public function __construct(
private readonly AccountProxyInterface $currentUser,
) {}
/**
* Implements hook_form_node_article_form_alter().
*
* Prefer targeted form hooks over generic form_alter — they only fire for
* the specific form ID and avoid unnecessary processing.
*/
#[Hook('form_node_article_form_alter')]
public function formNodeArticleFormAlter(array &$form, FormStateInterface $form_state): void {
$form['title']['#title'] = $this->t('Article title');
}
/**
* Implements hook_form_alter().
*
* Use only when acting on multiple forms or the form ID is unknown at
* development time. Check $form_id explicitly.
*/
#[Hook('form_alter')]
public function formAlter(array &$form, FormStateInterface $form_state, string $form_id): void {
if ($form_id === 'node_page_form') {
$form['title']['#description'] = $this->t('Enter a descriptive page title.');
}
}
#[Hook('node_presave')]
public function nodePresave(NodeInterface $node): void {
if ($node->getType() === 'article') {
// Example: stamp the current user's ID on save.
$node->set('uid', $this->currentUser->id());
}
}
#[Hook('theme')]
public function theme(): array {
return [
'my_template' => [
'variables' => ['content' => NULL],
],
];
}
}
> Note: If a hook is not executed, verify namespace and location. OOP hooks outside src/Hook/ require manual service registration.
services.yml
| Scenario | Required? | |---|---| | Class in src/Hook/, namespace Drupal\my_module\Hook | No — auto-registered (Drupal 11.1+) | | Class outside src/Hook/ (e.g. a custom service) | Yes — register manually |
When registration is needed — autowire resolves constructor dependencies by type hint:
namespace Drupal\my_module\Service;
use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\Session\AccountProxyInterface;
final class MyCustomService {
public function __construct(
private readonly AccountProxyInterface $currentUser,
) {}
#[Hook('form_alter')]
public function formAlter(...): void {
// ...
}
}
services:
Drupal\my_module\Service\MyCustomService:
autowire: true
Procedural Hooks (.module)
Auto-discovered via my_module_hook_name() naming. Still valid; prefer OOP hooks for new code.
Hooks vs Event Subscribers
| Use Hooks When | Use Event Subscribers When | |---|---| | form_alter, entity hooks, theme hooks | reacting to dispatched Symfony events | | extending Drupal core/contrib behavior | PSR-14 / decoupled systems | | working with existing Drupal APIs | building loosely coupled logic |
> OOP hooks in src/Hook/ are fully testable — instantiate the class directly and inject mocked dependencies.
RULES (IMPORTANT)
- ALWAYS prefer OOP hooks in
src/Hook/for new implementations - NEVER add new hooks in
.moduleunless explicitly requested - If procedural hook exists, suggest refactoring to OOP
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: edutrul
- Source: edutrul/drupal-ai
- License: MIT
- Homepage: https://eduardotelaya.com/drupal-ai/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.