Creating Custom Triggers¶
FlowDrop's trigger system is extensible via the FlowDropEventType plugin. You can define new event types that fire workflows in response to any Drupal event — Commerce orders, Webform submissions, custom module hooks, or anything else you can subscribe to.
Module Required
Custom event type plugins require the flowdrop_trigger module.
API Stability
FlowDropEventTypeInterface and TriggerManagerInterface are @api in the 1.x release line and covered by the BC policy.
How It Works¶
- You create a PHP class implementing
FlowDropEventTypeInterfacewith the#[FlowDropEventType]attribute. - FlowDrop discovers your plugin automatically via Drupal's plugin discovery.
- Your event type appears in the trigger node's configuration panel in the visual editor.
- When your Drupal event fires, you call
TriggerManagerInterface::processEvent()to dispatch it into FlowDrop.
Step 1: Create the Event Type Plugin¶
Create your class in src/Plugin/FlowDropEventType/ within your module:
<?php
declare(strict_types=1);
namespace Drupal\my_module\Plugin\FlowDropEventType;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\flowdrop_trigger\Attribute\FlowDropEventType;
use Drupal\flowdrop_trigger\Enum\EventCategory;
use Drupal\flowdrop_trigger\Enum\TriggerExecutionMode;
use Drupal\flowdrop_trigger\FlowDropEventTypeInterface;
use Drupal\flowdrop_trigger\Plugin\FlowDropEventTypeBase;
/**
* Event type for Commerce order placement.
*
* Triggers when a new order is placed via Drupal Commerce.
*
* @internal This class is not part of the public API.
*/
#[FlowDropEventType(
id: 'commerce.order.place',
label: new TranslatableMarkup('Commerce: Order Placed'),
description: new TranslatableMarkup('Triggered when a customer places a new order'),
category: EventCategory::Entity,
defaultOrchestrator: 'flowdrop_runtime:asynchronous',
defaultExecutionMode: TriggerExecutionMode::Async,
supportedEntityTypes: ['commerce_order'],
)]
class CommerceOrderPlace extends FlowDropEventTypeBase implements FlowDropEventTypeInterface {
/**
* {@inheritdoc}
*/
public function extractTriggerData(
?EntityInterface $entity,
?EntityInterface $originalEntity = NULL,
array $context = [],
): array {
if ($entity === NULL) {
throw new \InvalidArgumentException('Entity cannot be NULL for order events.');
}
// Build the data that will be available in the workflow.
return [
'event_type' => $this->getEventId(),
'order_id' => $entity->id(),
'order_number' => $entity->getOrderNumber(),
'order_total' => $entity->getTotalPrice()->getNumber(),
'currency' => $entity->getTotalPrice()->getCurrencyCode(),
'customer_id' => $entity->getCustomerId(),
'email' => $entity->getEmail(),
'timestamp' => time(),
];
}
/**
* {@inheritdoc}
*/
public function getParameterSchema(): array {
// Parameters available to configure in the trigger node panel.
return [
'type' => 'object',
'properties' => [
'min_order_total' => [
'type' => 'number',
'title' => 'Minimum order total',
'description' => 'Only trigger for orders above this amount (0 = all orders)',
'default' => 0,
],
],
];
}
}
#[FlowDropEventType] Attribute Parameters¶
| Parameter | Type | Required | Description |
|---|---|---|---|
id |
string | Yes | Unique event type ID (e.g., commerce.order.place) |
label |
TranslatableMarkup | Yes | Human-readable label shown in the editor |
description |
TranslatableMarkup | Yes | Shown in the trigger config panel |
category |
EventCategory | No | Groups events in the UI — Entity, User, Form, or Cron |
defaultOrchestrator |
string | No | Default orchestrator ID (default: flowdrop_runtime:asynchronous) |
defaultExecutionMode |
TriggerExecutionMode | No | Async or Sync (default: Async) |
supportedEntityTypes |
array | No | Restrict to specific entity types (empty = all) |
Step 2: Dispatch the Event¶
When your Drupal event fires, inject TriggerManagerInterface and call processEvent():
<?php
declare(strict_types=1);
namespace Drupal\my_module\EventSubscriber;
use Drupal\commerce_order\Event\OrderEvent;
use Drupal\flowdrop_trigger\Service\TriggerManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Dispatches FlowDrop triggers on Commerce order events.
*/
class CommerceOrderEventSubscriber implements EventSubscriberInterface {
public function __construct(
private readonly TriggerManagerInterface $triggerManager,
) {}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array {
return [
'commerce_order.place.post_transition' => 'onOrderPlace',
];
}
/**
* Fires FlowDrop triggers when an order is placed.
*/
public function onOrderPlace(OrderEvent $event): void {
$order = $event->getOrder();
$this->triggerManager->processEvent(
'commerce.order.place', // must match your plugin's id
$order,
[], // optional extra context
);
}
}
Register the subscriber in your module's services.yml:
services:
my_module.commerce_order_event_subscriber:
class: Drupal\my_module\EventSubscriber\CommerceOrderEventSubscriber
arguments: ['@flowdrop_trigger.trigger_manager']
tags:
- { name: event_subscriber }
Non-Entity Events¶
For events that are not entity-based (e.g., custom module hooks), use processCronEvent() or processFormEvent(), or call processEvent() with NULL as the entity and pass all data through the $context array.
Then in your plugin, read from $context in extractTriggerData():
public function extractTriggerData(
?EntityInterface $entity,
?EntityInterface $originalEntity = NULL,
array $context = [],
): array {
return [
'event_type' => $this->getEventId(),
'custom_data' => $context['my_custom_key'] ?? NULL,
'timestamp' => time(),
];
}
Accessing Trigger Data in a Workflow¶
The array returned by extractTriggerData() is passed as the initial data to the workflow. Use a Get Workflow Data node or Data Extractor node to access individual fields in your workflow nodes.
For the Commerce example above, a Data Extractor node can pull out order_id, order_total, email, etc.
Testing Your Event Type¶
Verify your plugin is discovered by FlowDrop:
# Open a workflow in the editor and add a Trigger node.
# Your event type should appear in the "Event Type" dropdown.
# Or confirm via Drush:
drush php:eval "
\$manager = \Drupal::service('plugin.manager.flowdrop_event_type');
print_r(array_keys(\$manager->getDefinitions()));
"
Trigger the event manually to test:
drush php:eval "
\$order = \Drupal::entityTypeManager()->getStorage('commerce_order')->load(1);
\$manager = \Drupal::service('flowdrop_trigger.trigger_manager');
\$manager->processEvent('commerce.order.place', \$order);
echo 'Trigger dispatched.';
"
Then check Administration > FlowDrop > Pipelines for the resulting execution.
Next Steps¶
- Node Processor Plugin System — Create custom nodes
- Creating Custom Orchestrators — Build custom execution strategies
- Setting Up Triggers — Trigger configuration UI guide