Weesperstraat 61-105
1018 VN Amsterdam
The Netherlands

AI / Vibe coding in Drupal, een praktijkvoorbeeld

AI als programmeer partner
26 Sep, 2026 Drupal
drupal_vibe_coding_header_evenementen

Een verzoek van een product owner: zijn Drupal website heeft een content-type Evenement. De redactie wil op de homepage een blok met de eerstvolgende drie evenementen tonen.

De initiële wens en AI prompt:

“Maak een Drupal block dat de eerstvolgende drie evenementen toont, gesorteerd op startdatum. Geef elk evenement een titel, datum en link. De evenementen moeten tevens gepubliceerd zijn. Houdt ook rekening met herhaalde evenementen. Graag 'programatically', niet in Views, omdat ik meer complexiteit en externe integraties verwacht later in dit ontwikkeltraject ”

In plaats van eerst alle code zelf uit te werken, kan een Drupal developer AI als programmeerpartner gebruiken. Dat is vibe coding: je beschrijft vooral wat je wilt bereiken, laat AI een eerste implementatie genereren, en ontwikkelt verder op basis van testen en feedback.

Stap 1 – De Drupal opdracht aan AI

Een eerste prompt kan bijvoorbeeld zijn:

Ik werk met Drupal 11.

Ik heb een contenttype 'Evenement' met de velden:
- field_start_date
- field_location

Maak een custom module 'event_teaser' met een block plugin.

Het block moet:
- de 3 eerstvolgende gepubliceerde evenementen ophalen;
- sorteren op field_start_date oplopend;
- titel, startdatum en locatie tonen;
- een link naar de node tonen;
- geen evenementen tonen als er geen toekomstige evenementen zijn.

Gebruik Drupal coding standards en dependency injection waar dat relevant is.
Geef de benodigde bestanden en code.

AI kan vervolgens bijvoorbeeld een modulestructuur voorstellen:

modules/custom/event_teaser/
├── event_teaser.info.yml
├── event_teaser.module
└── src/
    └── Plugin/
        └── Block/
            └── UpcomingEventsBlock.php

Stap 2 – De eerste code

Een vereenvoudigde block plugin kan er bijvoorbeeld zo uitzien, in eerste instantie gegenereerd door AI:

<?php

namespace Drupal\event_teaser\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides an Upcoming Events block.
 *
 * @Block(
 *   id = "upcoming_events",
 *   admin_label = @Translation("Upcoming events")
 * )
 */
class UpcomingEventsBlock extends BlockBase implements ContainerFactoryPluginInterface {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected EntityTypeManagerInterface $entityTypeManager;

  /**
   * Constructs the block.
   */
  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    EntityTypeManagerInterface $entity_type_manager,
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(
    ContainerInterface $container,
    array $configuration,
    $plugin_id,
    $plugin_definition,
  ) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('entity_type.manager'),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function build() {
    $storage = $this->entityTypeManager
      ->getStorage('node');

    $query = $storage->getQuery()
      ->accessCheck(TRUE)
      ->condition('type', 'evenement')
      ->condition('status', 1)
      ->condition('field_start_date', date('Y-m-d\TH:i:s'), '>=')
      ->sort('field_start_date', 'ASC')
      ->range(0, 3);

    $nids = $query->execute();

    $nodes = $storage->loadMultiple($nids);

    return [
      '#theme' => 'item_list',
      '#items' => array_map(
        fn($node) => [
          '#markup' => $node->toLink()->toString(),
        ],
        $nodes
      ),
    ];
  }

}

De vibe coding zit echter niet alleen in het genereren van deze code. Het interessante deel begint daarna.


Stap 3 – Testen

De developer installeert de module:

drush en event_teaser
drush cr

Daarna kan je het block binnen het backend in een Drupal region plaatsen, zodat deze zichtbaar wordt in het frontend.

Het frontend resultaat is dan bijvoorbeeld:

Aankomende evenementen

Drupal Meetup Amsterdam
15 oktober 2026

Web Accessibility Workshop
22 oktober 2026

Open Source Conference
4 november 2026

Maar tijdens het testen en code review vallen dingen meteen op:

  • de datum wordt bijvoorbeeld verkeerd weergegeven,
  • de locatie ontbreekt,
  • waarom wordt hier getQuery() gebruikt, en niet een entityQuery`?
  • en what the * bleep * doen fn($node) en array_map() hier?

Maar ook:

  • is de dependency injection wel correct gedaan,
  • hoe zit het met code security?
  • en veel meer (zie ook hieronder).

Je kunt de code ook nog door Drupal Coder module halen, ter review.


Stap 4 – Feedback geven aan AI

In plaats van zelf de hele implementatie opnieuw te schrijven, geeft de Drupal developer concrete feedback:

De eerste versie werkt, maar ik wil drie wijzigingen:

1. Gebruik Drupal's date formatter in plaats van date().
2. Toon field_location onder de titel.
3. Gebruik een aparte Twig-template file in plaats van #markup.
4. Wat doet "fn($node)" hier?

Pas de module aan en geef alleen de bestanden die moeten wijzigen.

AI kan vervolgens een Twig-template voorstellen:

event_teaser/
├── templates/
│   └── event-teaser-item.html.twig
└── src/
    └── Plugin/
        └── Block/
            └── UpcomingEventsBlock.php

Met bijvoorbeeld:

<article class="event-teaser">
  <h3>
    <a href="{{ url }}">{{ title }}</a>
  </h3>

  <time datetime="{{ datetime }}">
    {{ date }}
  </time>

  {% if location %}
    <div class="event-teaser__location">
      {{ location }}
    </div>
  {% endif %}
</article>

Stap 5 – Een probleem ontdekken

Tijdens code review merkt de Drupal developer op dat de query:

->condition(
  'field_start_date',
  date('Y-m-d\TH:i:s'),
  '>='
)

mogelijk niet goed aansluit bij het daadwerkelijke opslagformaat van het datumveld.

Dit is een belangrijk onderdeel van vibe coding:

AI genereert de code, maar de Drupal developer blijft verantwoordelijk voor de juistheid ervan.

De Drupal developer moet zelf de code kunnen testen en handmatig kunnen corrigeren, want AI kan ook nog flink hallucineren.

De developer kan AI daarom vragen:

Controleer deze query specifiek voor Drupal 11 en een
datetime field.

Leg uit welk formaat Drupal intern gebruikt voor
field_start_date en pas de query aan.

Geef ook aan welke aannames je maakt.

AI kan dan helpen de implementatie te corrigeren, maar de developer controleert vervolgens de oplossing tegen de daadwerkelijke Drupal configuratie en testdata.


Stap 6 – Een extra verbetering

Na de functionele versie komt een nieuwe wens:

“Kunnen we het aantal evenementen configureerbaar maken?”

De developer vraagt:

Maak het block configureerbaar.

De beheerder moet in de block configuration kunnen
kiezen hoeveel evenementen worden getoond, standaard 3.

Gebruik Drupal Form API en sla de configuratie op
als block configuration.

AI genereert vervolgens de benodigde blockForm(), blockSubmit() en aanpassingen aan build().

De developer hoeft daardoor niet elk stukje Drupal API-code uit het hoofd te kennen. Hij stuurt vooral het gewenste gedrag en beoordeelt de gegenereerde implementatie.

Ook hier geldt weer: de Drupal developer moet kunnen analyseren of de gegenereerde code in blockForm(), blockSubmit() en build() kloppen.


Wat maakt dit 'vibe coding'?

In een traditionele aanpak zou de developer bijvoorbeeld:

  1. de Drupal Block API documentatie opzoeken;
  2. de pluginstructuur maken;
  3. de dependency injection schrijven;
  4. de Entity Query opbouwen;
  5. een Twig-template maken;
  6. de configuration form schrijven;
  7. testen en debuggen.

Drupal console en Drush hielpen daar voorheen bij, maar vibe coding verschuift een deel van dat werk naar een gesprek met AI:

Developer
    │
    │  "Ik wil dit gedrag"
    ▼
AI
    │
    │  code + voorstel
    ▼
Developer
    │
    │  testen
    ▼
Probleem / feedback
    │
    └──────────────► AI
                       │
                       ▼
                   verbeterde code

De developer werkt dus meer als regisseur en reviewer en minder als iemand die iedere regel vanaf nul typt.


Waar moet je in Drupal extra op letten?

Vibe coding is vooral krachtig als de developer de Drupal best practices goed blijft bewaken.

Let bijvoorbeeld op:

  • Security — controleer input, permissions en output.
  • Drupal coding standards — laat gegenereerde code niet automatisch als correct beschouwen.
  • Upgradebaarheid — controleer of gebruikte API's daadwerkelijk bij de Drupal-versie passen.
  • Dependency injection — vermijd onnodig gebruik van globale services.
  • Configuration management — zorg dat instellingen exporteerbaar zijn.
  • Cacheability — blocks en entity queries moeten correct gecachet worden.
  • Access checking — bij alle 'Routes' en 'Entity Queries'.
  • Render arrays — vermijd onnodig HTML via #markup.
  • Twig escaping — laat Drupal het escapen van output afhandelen.
  • .. en vele andere Drupal best practices

De kern

Een goede Drupal-vibe-coding workflow is daarom niet:

“AI, bouw mijn Drupal website.”

Maar eerder:

“Ik beschrijf het gewenste gedrag → AI maakt een eerste implementatie → ik test → AI help mij verbeteren → ik review en accepteer de uiteindelijke code.”

Het voordeel zit vooral in de kortere feedbacklus. De Drupal developer kan sneller van idee naar werkende Drupal-code gaan, terwijl kennis van Drupal-architectuur, security en onderhoudbaarheid belangrijk blijft.

Full disclosure: dit blog is tevens vibe coded tot stand gekomen :)

AI Vibe coding
Written by Joris Snoek | Sep 26, 2026
Drupal project? Let's Talk

Vertel mij over jullie project, ik hoor het graag!
Mail , of stuur een bericht:

Got some more time?

Related content
26 May, 2021 Drupal

Met nieuwe functies als: @-mentions, drag-drop afbeeldingen & algemene instellingen.


06 Apr, 2021 Drupal


17 Aug, 2020 Drupal

Een Drupal Module Voorbeeld Inclusief Twig Template.