Skip to content

Hooks & filters

Yatra is built around a wide hook surface: every meaningful state change fires an action, and most rendered values pass through a filter so you can override them. This page lists the most useful actions and filters grouped by area, plus general guidance on using them.

Yatra exposes hundreds of hooks. The list below covers the ~80 you'll reach for most often.

Verify hook names against your version

Hook names can be added, renamed, or retired between plugin versions. Before you build something that depends on a specific hook, confirm it exists in your version by searching the plugin source:

bash
grep -rh "do_action.*yatra_booking_created" wp-content/plugins/yatra wp-content/plugins/yatra-pro
grep -rh "apply_filters.*yatra_trip_price" wp-content/plugins/yatra

Every Yatra hook follows the yatra_* prefix.

Conventions

  • Actions are named yatra_{noun}_{verb} and fire after the underlying change (e.g. yatra_booking_created fires after the booking row is inserted).
  • Filters are named yatra_{noun}_{property} and pass the value as the first argument.
  • Pro hooks carry no special prefix — Pro just adds more yatra_* hooks. A few pro-specific hooks use yatra_pro_* (license, module activation).
  • Backwards compatibility: Yatra retires hooks with notice, never silently. Deprecated hooks keep firing for at least one minor version.

Trips

Fired around trip lifecycle and rendering.

HookTypePurpose
yatra_trip_createdactionAfter a trip is inserted; receives $trip_id
yatra_trip_updatedactionAfter a trip is updated
yatra_trip_deletedactionBefore a trip is deleted (soft or hard)
yatra_trip_loaded_with_relationsfilterMutate the joined trip object (with classifications, attributes, etc.)
yatra_trip_created_with_relationsactionAfter insert + relations save
yatra_trip_updated_with_relationsactionAfter update + relations save
yatra_trip_display_pricefilterLast-mile override for the displayed price
yatra_dynamic_pricing_enabledfilterToggle Pro Dynamic Pricing per-trip
yatra_availability_pricefilterOverride price on a specific departure
yatra_get_dynamic_pricing_display_settingsfilterCustomize how dynamic-pricing surcharges/discounts render
yatra_calculate_demand_scoresactionOverride demand-score calculation (Pro)

Bookings

Lifecycle and per-booking rendering.

HookTypePurpose
yatra_booking_createdactionNew booking submitted
yatra_booking_updatedactionBooking row updated
yatra_booking_status_changedactionArgs: ($booking, $new_status, $old_status)
yatra_booking_deletedactionBefore a booking is deleted
yatra_booking_email_variablesfilterAugment the merge-tag map for booking emails
yatra_booking_email_traveler_identity_field_keysfilterCustomize identity-table fields
yatra_payment_completedactionFired across multiple gateways after capture

Booking pricing pipeline

The price you see on the booking summary is the result of a chain of filters. Hooking these lets you adjust the math without touching gateway code.

FilterStage
yatra_before_calculation_paramsNormalize incoming traveler counts, picked date, etc.
yatra_booking_trip_pricePer-trip base price
yatra_calculate_subtotalAfter traveler categories, before extras
yatra_booking_additional_servicesPro Additional Services subtotal
yatra_calculate_payment_amountsCompute deposit / partial / total payable now
yatra_after_calculation_resultFinal adjustments
yatra_booking_email_variablesVariables passed to email templates

The implementation lives in app/Services/CalculationService.php. Each filter receives the partial result and the booking context.

Payments

HookTypePurpose
yatra_register_payment_gatewaysactionRegister a custom gateway class
yatra_payment_gateway_config_savedactionAfter a gateway's settings save
yatra_before_payment_processingactionBefore a payment intent is created
yatra_payment_completedactionAfter successful capture
yatra_payment_failedactionAfter failed capture
yatra_after_payment_processingactionFinal hook after payment processing succeeds
yatra_paypal_payment_completedactionPayPal-specific success
yatra_paypal_payment_refundedactionPayPal-specific refund (use this instead of a generic yatra_payment_refunded — Yatra fires per-gateway refund actions)
yatra_razorpay_refund_createdactionRazorpay-specific refund
yatra_payment_amount_mismatchaction(3.0.4+) Fires when a client-supplied amount in POST /payment/create-intent disagreed with the server's booking.amount_due. Args: ($booking_id, $client_amount, $server_amount). The transaction itself is forced to the server amount; this hook exists for fraud-monitoring integrations.
yatra_pdf_remote_enabledfilter(3.0.4+) Enable / disable dompdf remote image loading. Default true so PDFs can render the site logo and trip images. Return false to lock the PDF generator down to ABSPATH only (recommended if your invoices never contain external images).
yatra_pro_writable_settings_schemafilter(3.0.4+) Pro-only. Receives key => sanitizer-callable map of settings keys the POST /yatra/v1/settings REST endpoint is allowed to write. Modules can register their own keys here; anything not in this map is silently rejected by the endpoint.
yatra_pass_gateway_ids_for_scheduled_paymentsfilterWhether to forward the gateway's customer / payment-method IDs into the scheduled-payments pipeline even when save_card was off. Useful for gateways that auto-vault.

Stripe-specific actions (Pro)

Fired only when the verified Stripe webhook handler dispatches a known event. Verification is HMAC-SHA256 against the configured webhook_secret with a 5-minute replay window — handlers attached here only ever see real, signed Stripe events.

HookTypePurpose
yatra_stripe_payment_succeededaction(3.0.4+) payment_intent.succeeded. Receives the full PaymentIntent object as an array.
yatra_stripe_payment_failedaction(3.0.4+) payment_intent.payment_failed. Args: PaymentIntent object as array.
yatra_stripe_charge_refundedaction(3.0.4+) charge.refunded. Args: Charge object as array.

Adding a custom gateway

The minimal recipe:

php
add_action( 'yatra_register_payment_gateways', function ( $registry ) {
    $registry->register( 'my_gw', \My\Gateway\MyGateway::class );
} );

Your MyGateway extends \Yatra\PaymentGateways\AbstractPaymentGateway and implements id, name, description, getConfigFields, processPayment, optionally processRefund and handleWebhook. See app/PaymentGateways/Gateways/PayPal/PayPalGateway.php for a complete reference.

Email

HookTypePurpose
yatra_email_merge_tag_definitionsfilter(3.0.5+) Central merge-tag registry. Append / amend rows in Yatra\Services\EmailMergeTagRegistry. Tags added here automatically surface in the Pro Template Editor sidebar for every event they declare in events. Must be paired with a dispatcher-side injection (e.g. yatra_booking_email_variables) so the value actually renders.
yatra_email_template_variables_catalogfilter(3.0.5+) Legacy hook — applied AFTER the registry is grouped for the REST /email-templates/variables endpoint. Prefer yatra_email_merge_tag_definitions for new code.
yatra_email_event_variablesfilter(3.0.5+) Extend the per-event variable whitelist for a single event. Args: (array $keys, string $eventKey). Keys not already in the registry surface in an "event-specific" group on the sidebar.
yatra_send_transactional_emailfilterShort-circuit before sending; return false to suppress
yatra_pro_email_automation_owns_transactional_typefilterLet Pro Email Automation own a specific template type
yatra_booking_email_variablesfilterFinal mutation point for booking-event variables (after variablesFromBooking() + rich tags). Args: (array $variables, object $booking).
yatra_email_template_trip_variablesfilterAdd or rewrite the per-trip merge tags available to email templates
yatra_email_template_preview_variablesfilterSame, for the template preview pane
yatra_send_booking_status_email_htmlfilterRendered HTML for booking-status emails before send
yatra_email_template_enquiry_admin / _received / _responsefilterOverride the rendered HTML per enquiry email template

Adding a merge tag end-to-end

The registry is the single source of truth — adding a tag means registering it AND wiring up the dispatcher value. Skip step 2 and your tag will render as an empty string; skip step 1 and the sidebar won't surface it.

php
// 1. Declare the tag so the editor sidebar lists it for the right events.
add_filter( 'yatra_email_merge_tag_definitions', function ( array $catalog ) {
    $catalog['gst_invoice_number'] = [
        'key'         => 'gst_invoice_number',
        'label'       => 'GST Invoice Number',
        'description' => 'Tax-invoice number printed on the GST receipt.',
        'category'    => 'booking',
        'sample'      => 'GST-2025-00042',
        'events'      => [ 'booking.created', 'booking.confirmed', 'payment.received' ],
    ];
    return $catalog;
} );

// 2. Inject the real value so the rendered email actually contains it.
add_filter( 'yatra_booking_email_variables', function ( array $vars, $booking ) {
    $vars['gst_invoice_number'] = (string) get_post_meta( $booking->id, '_gst_invoice_number', true );
    return $vars;
}, 10, 2 );

Enquiries

HookTypePurpose
yatra_enquiry_createdactionAfter enquiry insert (carries the joined trip object since 3.0.3)
yatra_enable_enquiryfilterMaster toggle for enquiry UI on the trip page
yatra_enquiry_button_textfilterCustomise the "Make an Enquiry" CTA copy
yatra_enquiry_form_showfilterShow / hide the enquiry form per trip
yatra_enquiry_form_title_textfilterOverride the enquiry form title
yatra_email_template_enquiry_adminfilterRendered HTML for the admin enquiry notification
yatra_email_template_enquiry_responsefilterRendered HTML for the customer response email

Account / customer

HookTypePurpose
yatra_customer_createdactionNew customer record
yatra_customer_updatedactionAfter customer edit
yatra_user_idfilterResolve the user ID for a customer / booking flow
yatra_user_allowed_to_loginfilterBlock / allow a specific user from the front-end login flow
yatra_login_redirect_urlfilterRedirect destination after a successful login

Front-end routing & templates

Yatra registers its own pretty URLs for the booking flow, account, email verification and remaining-balance checkout.

HookTypePurpose
yatra_pretty_route_matchfilterModify how a route resolves (final say on tab/template)
yatra_plain_route_matchfilterSame but for ?yatra_* query-string URLs
yatra_frontend_request_pathfilterNormalize the request path before matching
yatra_register_rewrite_rulesactionAdd additional rewrite rules
yatra_build_archive_listing_urlfilterOverride how Yatra builds catalog listing URLs
yatra_get_trip_listing_urlfilterOverride the URL Yatra generates for the trip archive

Shortcodes and listings

HookTypePurpose
yatra_trip_listingfilterThe full listing object Yatra renders into the trip catalog
yatra_trip_listing_contextfilterThe context array passed to the trip card template
yatra_trip_listing_max_per_pagefilterCap on the per_page shortcode attribute
yatra_is_trip_listingfilterOverride Yatra's "are we on the trip-listing page" detection
yatra_listing_noncefilterCustomise the nonce field used inside listing-form posts

Want to customise card markup?

Yatra doesn't currently expose a stable *_card_html filter for whole-card replacement. The supported customisation paths are: (1) override the card template in your child theme — copy templates/partials/trip-card.php into wp-content/themes/{your-theme}/yatra/partials/trip-card.php; or (2) hook into the listing-context filter above to mutate the variables the card template sees.

Frontend templating & block themes (FSE)

Yatra renders its own URL paths (/trips/, /trip/{slug}/, /book/, /my-account/, etc.) with a custom router rather than via real WordPress post types. The following extension points exist so themes and other plugins can integrate cleanly — particularly with Full Site Editing block themes.

HookTypePurpose
pre_handle_404 (core hook, Yatra uses)filterYatra short-circuits this for its own URLs so WP::handle_404() never sets is_404 = true for plugin pages. Return true from your own callback (priority < 10) to opt a custom URL in.
body_classfilterYatra strips error404 for its pages and adds yatra-page plus a yatra-page-{type} class (e.g. yatra-page-trip).
template_includefilterYatra hooks at priority 99. If a request matched a Yatra route, the chosen PHP template is returned here. Customise via yatra_template_path below or with a theme override at your-theme/yatra/{template}.php.
yatra_template_pathfilter($absolute_path, $template_name, $page_type) — last chance to swap the PHP file before it's included. Useful for shipping a template variant from another plugin.
yatra_register_rewrite_rulesactionFires after Yatra registers its rewrite tags and rules. Receives the resolved permalink bases.

FSE / Site Editor

Yatra registers virtual block templates (Single Trip, Trip Listing, Destination, Activity, Booking, Booking Confirmation, My Account) so admins can find and customise Yatra layouts under Appearance → Editor → Templates.

  • The customisation is saved by core as a wp_template post. On the next request, Yatra detects it and renders that block template instead of the bundled PHP template.
  • Block templates embed a server-side block called Yatra Page Content (yatra/page-content). At render time it includes the PHP template selected by Yatra's router, so customising the chrome (header / sidebar / footer placement) is fully editable while the content stays driven by Yatra.
  • Inside that block, yatra_get_header() and yatra_get_footer() are no-ops — the canvas already emits the document and header/footer parts, so the PHP template only contributes its inner content.

Theme overrides without the editor

Drop a copy of any template at wp-content/themes/{your-theme}/yatra/{name}.php and locate_template() will pick it up first. No filter wiring needed. This works for classic and block themes alike.

Admin / settings / modules

HookTypePurpose
yatra_admin_localized_datafilterInject extra props into window.yatraAdmin. Pro modules use this to expose flags like flexiblePaymentsEnabled so the React admin can conditionally render Pro-gated UI.
yatra_module_activeactionWhen a module is enabled
yatra_module_deactiveactionWhen a module is disabled
yatra_module_enabled_statusfilterAuthoritative is-this-module-enabled check
yatra_module_capabilitiesfilterModule-required capabilities
yatra_module_assetsfilterAssets enqueued for a module
yatra_default_modulesfilterAdd to / remove from the default module registry
yatra_enable_setup_wizardfilterShow / hide the setup wizard
yatra_clear_cacheactionInvalidate Yatra's internal cache

Pro license & updater

HookTypePurpose
yatra_is_pro_activefilterToggle Pro behavior (Pro returns true; you can short-circuit for testing)
yatra_pro_available_modulesfilterAdd or remove modules from the Modules screen
yatra_pro_license_store_urlfilterOverride the license store URL
yatra_pro_license_item_idfilterOverride the EDD product ID
yatra_pro_license_data_updatedactionAfter license data is saved
yatra_pro_module_activatedactionAfter a Pro module activates (creates tables, etc.)
yatra_pro_module_settings_updatedactionAfter a Pro module's settings save

Pro: Dynamic Pricing

HookTypePurpose
yatra_dynamic_pricing_enabledfilterWhether DP applies to a given trip
yatra_get_dynamic_pricing_display_settingsfilterDisplay settings for surcharge/discount badges
yatra_price_breakdownfilterThe breakdown shown on the booking summary
yatra_calculate_demand_scoresactionOverride / extend demand calculation

Pro: Flexible / Scheduled Payments

HookTypePurpose
yatra_flexible_payments_enabledfilterMaster toggle (per-trip or globally)
yatra_flexible_payment_settingfilterRead individual setting values
yatra_deposit_percentagefilter($default, $context = []) — Override deposit %. $context['trip_id'] lets the Pro module honour per-trip trip.deposit_percentage
yatra_partial_payment_percentagefilter($default, $context = []) — Override partial-payment % (context unused today; passed for parity)
yatra_calculate_amount_duefilter($amount_due, $total_amount, $payment_method, $context = []) — Final say on the payable-now amount. $context['trip_id'] lets Pro apply per-trip trip.deposit_amount (absolute) or trip.deposit_percentage
yatra_payment_method_optionsfilter($options, $booking_data) — Adds Pay X% Deposit / Pay X% Now radios to the booking form. $booking_data['trip_id'] lets Pro show the deposit option whenever a trip has per-trip values, even with the global flag off
yatra_scheduled_payments_module_activefilterWhether scheduled payments processing should run
yatra_scheduled_payment_settingfilterPer-setting reads

Per-trip overrides

The $context argument added to yatra_deposit_percentage, yatra_calculate_amount_due, and yatra_payment_method_options since Yatra Free 3.0.5 / Pro 3.0.3 is what lets the Flexible Payments module read trip.deposit_amount / trip.deposit_percentage for a specific booking. If you implement your own filter callback that ignores $context, you'll only get site-wide behaviour — which is fine, but match the new signature if you want trip-aware behaviour.

Pro: Email Automation

HookTypePurpose
yatra_pro_email_automation_owns_transactional_typefilterLet Pro Email Automation own a specific template type so Pro's send pipeline runs instead of the free one

Looking for sequence-step or payload filters?

Yatra's source emits sequence events through the email-template filter chain (see the Email section above). If you need pre-send mutation, hook into yatra_send_transactional_email (returns false to suppress) or the per-template filters like yatra_email_template_trip_variables.

Pro: Custom Landing Pages

HookTypePurpose
yatra_destination_permalinkfilterOverride the destination URL
yatra_activity_permalinkfilterOverride the activity URL
yatra_category_permalinkfilterOverride the trip-category URL
HookTypePurpose
yatra_consent_signedactionAfter a customer signs a consent form

Customise consent email copy

The consent-request email is a normal Yatra template (trip_consent_request). Override the body via Settings → Email → Templates, or hook into yatra_email_template_trip_variables to rewrite the merge-tag values it receives.

Pro: Additional Services

HookTypePurpose
yatra_booking_additional_servicesfilterMutate selected services on a booking
yatra_booking_save_servicesactionAfter services are persisted
yatra_booking_get_servicesfilterModify how services are fetched for display

Practical recipes

Send a Slack notification on every booking

php
add_action( 'yatra_booking_created', function ( $booking_id ) {
    $booking = yatra_get_booking( $booking_id );
    if ( ! $booking ) return;

    wp_remote_post( SLACK_WEBHOOK_URL, [
        'body'    => wp_json_encode( [
            'text' => sprintf(
                'New booking %s for %s · %d travelers · %s',
                $booking->reference,
                $booking->trip_title,
                $booking->traveler_count,
                yatra_price_html( $booking->total )
            ),
        ] ),
        'headers' => [ 'Content-Type' => 'application/json' ],
    ] );
}, 10, 1 );

Add 5% surcharge to all bookings on weekends

php
add_filter( 'yatra_booking_trip_price', function ( $price, $context ) {
    $departure = $context['departure_date'] ?? null;
    if ( ! $departure ) return $price;

    $day = (int) date( 'N', strtotime( $departure ) );
    if ( $day >= 6 ) {                  // Sat / Sun
        $price *= 1.05;
    }
    return $price;
}, 10, 2 );

Hide trips from a specific destination on a public listing

php
add_filter( 'yatra_trip_listing_filters', function ( $filters ) {
    if ( is_admin() || ! empty( $filters['private_view'] ) ) return $filters;

    $filters['exclude_destination'] = [ 99 ];   // hide destination ID 99 from public listings
    return $filters;
} );

Auto-tag Mailchimp subscribers based on the trip booked

php
add_action( 'yatra_booking_created', function ( $booking_id ) {
    $booking = yatra_get_booking( $booking_id );
    if ( ! $booking ) return;

    $tag = sprintf( 'trip-%s', sanitize_title( $booking->trip_title ) );
    do_action( 'yatra_mailchimp_add_tag', $booking->customer_email, $tag );
} );

Block weekend bookings of a specific trip

php
add_filter( 'yatra_resolve_availability_object', function ( $availability, $trip_id, $date ) {
    if ( $trip_id !== 42 ) return $availability;
    $day = (int) date( 'N', strtotime( $date ) );
    if ( $day >= 6 ) {
        $availability['available'] = false;
        $availability['message']   = 'This trip runs Mon–Fri only.';
    }
    return $availability;
}, 10, 3 );

Discovering more hooks

bash
cd wp-content/plugins/yatra
# All actions:
grep -rn "do_action\(\s*'yatra_" app/ | sort -t: -k1
# All filters:
grep -rn "apply_filters\(\s*'yatra_" app/ | sort -t: -k1

Most hooks have a short docblock explaining the arguments and intent. The cleanest summary lives at the call site rather than in a separate hook reference, so reading the source is the canonical move when you're stuck.