Change record status: 
Introduced in branch: 
1.0.x
Introduced in version: 
1.0.0-beta7
Description: 

Before 1.0.0-beta7 a visitor to /subscription-manager/subscribe on a site with several connectors chose a connector and was sent to that connector's own plan picker. From beta7 the page offers plans, grouped by connector, and sends the visitor to the checkout for the plan they chose (#3629242: Let subscribers choose a plan, not a connector: list plans in the subscribe flow and preselect the plan in redirectToSubscribe()).

For site builders

The chooser shows one collapsible group per connector that has at least one enabled plan marked Show on subscribe blocks, in the order of the Connector chooser rows on the settings form, with each row's label and description as the group's heading. Inside, the connector's plans by weight then name, each with its price when the connector can give one. The default connector's group is open and marked "Recommended"; every other group is collapsed, deliberately, so that reaching a non-default rail takes one extra click. A subscriber who comes back to change plan (?change=1) sees their own connector's group open instead, with their current plan marked. With a single plan on offer across the site the chooser is skipped and the visitor goes straight to its checkout, as before with a single connector.

Links may name the choice: /subscription-manager/subscribe?connector=ID&plan=PLAN_ID starts the checkout for that plan when it is enabled and shown on an available connector; ?connector=ID alone narrows the chooser to that connector (or hands over its only plan). Anything invalid falls back to the chooser.

For themers

The subscription_manager_connector_chooser theme hook and subscription-manager-connector-chooser.html.twig are removed, replaced by subscription_manager_plan_chooser and subscription-manager-plan-chooser.html.twig. A theme overriding the old template must provide the new one; its single variable is groups, each with id, label, description, recommended, current, expanded and plans (plan_id, name, price_label, price, current, url). The default template renders a <details> per group with the open attribute on the expanded one, under the subscription-manager-plan-chooser class family.

For connector authors

Breaking: SubscriptionManagerConnectorInterface::redirectToSubscribe($user) is now

public function redirectToSubscribe($user, ?SubscriptionPlanEntity $plan = NULL): RedirectResponse;

PHP requires every connector to adopt the signature. When a plan is given, start the checkout for it: a Stripe connector creates the checkout session for the plan's price instead of showing its pricing table; a charge-based connector calls its instrument setup for that plan. When no plan is given (an existing subscriber returning to their connector's flow), behave as before. A connector whose service has no per-plan checkout may ignore the plan and send the visitor to its own picker, and should say so in its documentation.

Optional: PlanPricingConnectorInterface with one method, getPrice(SubscriptionPlanEntity $plan): ?PlanPrice. PlanPrice carries the amount as a decimal string in major units, the ISO 4217 currency, the interval (monthly or yearly), the interval count, and an optional free-text description shown in place of the structured fields. Return NULL for a plan the connector cannot price; it is listed without one. Connectors that do not implement the interface have all their plans listed without prices.

Off-site redirects from redirectToSubscribe() should be a \Drupal\Core\Routing\TrustedRedirectResponse, as for the hosted flows (see the beta7 change record for #3621280: Add update-path and browser test coverage from a pre-roadmap database fixture).

Redirects a connector returns from redirectToSubscribe(), redirectToPortal() and replaceInstrument() are passed through as trusted and uncacheable by Subscription Manager, so a connector need not add cacheability metadata to them; a plain RedirectResponse to another host is accepted and made trusted. A connector that was itself setting cache contexts on these responses can stop.

For decoupled front ends

When GET /subscription-manager/api/subscribe-url has a choice to offer, each entry of connectors[] now reads

{
  "id": "…", "label": "…", "description": "…",
  "recommended": true, "current": false, "expanded": true,
  "plans": [
    {
      "plan_id": "…", "name": "…",
      "price": {"amount": "10.00", "currency": "CAD", "interval": "monthly", "interval_count": 1, "description": null},
      "current": false,
      "subscribe_url": "https://example.com/subscription-manager/api/subscribe-url?connector=…&plan=…"
    }
  ]
}

price is null when unknown. The connector-level subscribe_url is gone: follow a plan's URL, which returns the single-URL shape for that plan's checkout. The single-URL shape itself is unchanged.

Impacts: 
Site builders, administrators, editors
Module developers
Themers