Subscriptions are handled by a subclass of EDD Recurring’s gateway, loaded only when EDD Recurring is active.
Recurring_Gateway overrides
| Method / hook | Behaviour |
|---|---|
init() | id = paddle; hooks edd_subscription_completed (stop billing in Paddle when bill times are reached) and edd_recurring_customer_update_uri_paddle |
$offsite = true | Order and subscriptions stay pending until Paddle confirms |
can_purchase_multiple_subs() | false |
can_cancel(), cancel(), cancel_immediately() | Only for linked Paddle subscriptions; respect Orders::$skip_remote_cancel; a per-request list prevents double API calls; transient wpinterface_paddle_cancelling_{id} tells a webhook arriving mid-request not to cancel again; failures set needs_attention |
can_update() | Billing: unless wpinterface_paddle_disable_customer_portal; Classic: when an update_url is stored |
update_payment_method_form() / update_payment_method() | EDD’s update page shows a note; after EDD verifies the buyer (owner or secure token), the buyer is redirected to Paddle’s page (management_urls.update_payment_method for Billing, update_url for Classic) |
customer_update_uri() | Makes EDD Recurring’s secure update links valid (Classic: update_url; Billing: non-empty only while can_update()) |
get_expiration() | Paddle’s next billing date (EDD Recurring calls it before expiring a subscription) |
link_profile_id(), link_transaction_id() | Dashboard links |
Status mapping
| Paddle | EDD |
|---|---|
| First payment confirmed | pending → active (trialling when the subscription has a trial) |
| Renewal paid | renew() → active, new expiration |
| Past due / payment failed | failing (+ edd_recurring_payment_failed) |
| Recovered (active again) | failing → active |
| Cancelled / scheduled cancel | cancelled (expiration kept; set to now if it was failing) |
| Paused | Status unchanged; meta _wpinterface_paddle_paused; EDD expires it at the expiration date if it is not resumed |
Expirations are stored in site-local time (EDD Recurring compares them with current_time()). Paddle’s UTC timestamps are converted with Orders::local_date().
Pause and resume
The admin panel (edd_subscription_card_top) posts to admin-post.php?action=wpinterface_paddle_pause (nonce wpinterface_paddle_pause_{id}, capability edit_shop_payments).
- Billing pauses with
effective_from: next_billing_period. Resume callsPOST /resumeif the subscription is paused, orPATCH { scheduled_change: null }if a pause is only scheduled. - Classic uses
subscription/users/updatewithpause=true|false(not allowed during trials, so the button is hidden then).