Recipe: Hook Into Checkout
Goal: Run code at three moments in the paid order lifecycle - before an order is created (to validate or modify), when an order is paid, and when an order is refunded.
Pro context: Checkout is a Pro feature. These hooks fire only when Eventonomy Pro is active and a paid ticket is purchased. On the Free plan, orders can exist as $0 records but no gateway payment hooks fire.
Seams Used
| Seam | Type | When it fires |
|---|---|---|
evnm_before_create_order |
Filter | Before the order row is inserted. Return WP_Error to abort. |
evnm_after_create_order |
Action | After the order row is inserted (status is typically pending). |
evnm_after_update_order |
Action | When an order field changes - including the status flip to paid. |
evnm_before_refund_order |
Filter | Before a refund is issued. Return WP_Error to abort. |
evnm_after_refund_order |
Action | After the gateway refund() call succeeds. |
Step 1 - Validate Before Creation
add_filter( 'evnm_before_create_order', function ( array $order, array $context ): array {
// Block orders from a specific email domain.
$email = (string) ( $order['email'] ?? '' );
if ( str_ends_with( $email, '@blocked.example.com' ) ) {
return new \WP_Error(
'my_addon_blocked_email',
__( 'Orders from this email domain are not accepted.', 'my-addon' ),
[ 'status' => 422 ]
);
}
return $order;
}, 10, 2 );
Step 2 - React When an Order Is Paid
The evnm_after_update_order action fires every time any order field changes. Check $changed_keys for 'status' and confirm the new status is 'paid':
add_action( 'evnm_after_update_order', function ( array $order, array $changed_keys, array $context ): void {
if ( ! in_array( 'status', $changed_keys, true ) || 'paid' !== $order['status'] ) {
return;
}
// Grant a perk for each ticket in the order.
foreach ( $order['line_items'] as $line ) {
my_addon_grant_perk( $order['user_id'], (int) $line['ticket_id'], (int) $line['quantity'] );
}
// Send to external CRM.
my_addon_push_order_to_crm( $order );
}, 10, 3 );
$order contains the full order row including id, status, total, currency, user_id, event_id, and line_items.
Step 3 - React When an Order Is Refunded
add_action( 'evnm_after_refund_order', function ( array $order, int $refunded_cents, array $context ): void {
my_addon_revoke_perk( $order['user_id'], $order['id'] );
my_addon_log_refund( $order['id'], $refunded_cents, $order['currency'] );
}, 10, 3 );
The line_items Shape
// Each element in $order['line_items']:
[
'ticket_id' => 42,
'name' => 'General Admission',
'quantity' => 2,
'unit_price' => 2500, // in minor units (cents)
'total' => 5000,
]
Prices are in the order's currency minor units (e.g. cents for USD). Use evnm_format_money() to convert to a display string.
Reading Order Data
Always resolve the order repository through the contract - never new a concrete:
$repo = evnm( \Eventonomy\Contracts\OrderRepositoryInterface::class );
$order = $repo->get( $order_id );
Verify It Worked
- Create a test event with a paid ticket.
- Complete checkout using a Stripe test card (
4242 4242 4242 4242). - Check that your
evnm_after_update_ordercallback fired: look inwp-content/debug.logor query your CRM/perk store. - Issue a refund from the Stripe Dashboard and confirm
evnm_after_refund_orderfired.
Related
docs/EXTENDING.mdยง2.2 - full RSVP / Ticket / Order / Occurrence hook signatures.- Payment Gateways - gateway setup.
- Recipes Index