Subscription internals

Updated

Subscriptions are handled by a subclass of EDD Recurring’s gateway, loaded only when EDD Recurring is active.

Recurring_Gateway overrides

Method / hookBehaviour
init()id = paddle; hooks edd_subscription_completed (stop billing in Paddle when bill times are reached) and edd_recurring_customer_update_uri_paddle
$offsite = trueOrder 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

PaddleEDD
First payment confirmedpending → active (trialling when the subscription has a trial)
Renewal paidrenew() → active, new expiration
Past due / payment failedfailing (+ edd_recurring_payment_failed)
Recovered (active again)failing → active
Cancelled / scheduled cancelcancelled (expiration kept; set to now if it was failing)
PausedStatus 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 calls POST /resume if the subscription is paused, or PATCH { scheduled_change: null } if a pause is only scheduled.
  • Classic uses subscription/users/update with pause=true|false (not allowed during trials, so the button is hidden then).

Was this page helpful?