AgentStack
SKILL verified MIT Self-run

Drupal Hooks

skill-edutrul-drupal-ai-drupal-hooks · by edutrul

Drupal 11 OOP and procedural hooks — hook_form_alter, hook_node_presave, hook_theme, #[Hook] attribute, and when to use hooks vs event subscribers.

No reviews yet
0 installs
10 views
0.0% view→install

Install

$ agentstack add skill-edutrul-drupal-ai-drupal-hooks

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No 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.

Are you the author of Drupal Hooks? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

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 .module unless 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.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.