Skip to main content

PodcastPaymentGateway Interface

Benecaster\Payment\PodcastPaymentGateway

The payment gateway contract that all gateway implementations must satisfy. Core ships StripeGateway (slug benecaster_stripe); the PayPal Gateway add-on ships PayPalGateway (slug benecaster_paypal). Third-party developers implement this interface to add custom payment processors.

Phase 2. All implementing classes are registered with PaymentGatewayRegistry.

Interface Methods

get_gateway_slug(): string
Returns the stable slug identifying this gateway. Used by PaymentGatewayRegistry for routing. Must be unique across all registered gateways. Convention: benecaster_{processor} (e.g., benecaster_stripe, benecaster_paypal).

is_test_mode(): bool (mandatory — PHP fatal if omitted)
Returns whether the gateway is currently operating in test mode. This method is mandatory. A concrete class that omits is_test_mode() raises a PHP fatal at class load — the interface declares it with no default body, which is language-level enforcement.

For StripeGateway, this returns the state of the benecaster_stripe_test_mode option (set by the Test Mode toggle in Settings → Membership → Payments).

The return value of is_test_mode() drives:

  • The persistent orange TEST MODE badge on all Benecaster admin screens.
  • The “Test Mode — payments are not real” banner on the subscriber account page.
  • Benecaster’s staging-vs-live safety checks.

If your gateway’s test mode is controlled by an option, read that option here. If your gateway has no test mode concept, return false.

create_subscription(): \Stripe\Subscription
Creates a new subscription for a subscriber. Receives billing details from NativeBridge::on_subscription_created(). Returns the gateway’s subscription object.

cancel_subscription(): \Stripe\Subscription
Cancels an existing subscription. Default behaviour for StripeGateway: cancel_at_period_end = true so feed access continues to the end of the current billing period. Implement immediate cancellation only if your gateway billing model requires it.

update_payment_method(): void
Updates the payment method on a subscriber’s account. For Stripe, this uses a SetupIntent flow. Called from the subscriber account page when the subscriber clicks “Update payment method.”

get_billing_history(): array
Returns a paginated list of invoices or billing events for a subscriber. Displayed on the subscriber account page. Return an array of objects with at minimum: date, amount, currency, status, invoice_url.

handle_webhook( \Stripe\Event $event ): void
Handles a raw event from the payment provider. For StripeGateway, this fires the appropriate benecaster_stripe_membership_* routing action. Implement this to route your gateway’s webhook events into Benecaster’s subscription lifecycle.

Registering a Custom Gateway

Register your implementation via benecaster_boot:

add_action( 'benecaster_boot', function ( \Benecaster\Container $container ): void {
    $container
        ->make( \Benecaster\Payment\PaymentGatewayRegistry::class )
        ->register( $container->make( My\CustomGateway::class ) );
} );

class CustomGateway implements \Benecaster\Payment\PodcastPaymentGateway {
    public function get_gateway_slug(): string { return 'benecaster_custom'; }
    public function is_test_mode(): bool { return (bool) get_option( 'my_gateway_sandbox_mode', false ); }
    // ... implement remaining methods
}

Once registered, your gateway appears in the Settings → Membership → Payments gateway selector alongside StripeGateway. The TEST MODE badge lights up if is_test_mode() returns true for the active gateway.

Notes

  • StripeGateway is registered automatically by core and is always available when Built-in Membership is active. You cannot deregister it.
  • The PayPal Gateway add-on registers PayPalGateway via the same pattern. See PayPal Gateway.
  • Subscription lifecycle methods (create_subscription, cancel_subscription, update_payment_method, get_billing_history) are stubbed in the Foundation batch and wired in the Lifecycle batch. Custom gateways implementing the full interface before Lifecycle ships will have their methods called once Lifecycle is active.