Subscriptions in Hydrogen
This recipe lets you sell subscription-based products on your Hydrogen storefront by implementing selling plan groups. Your customers will be able to choose between one-time purchases or recurring subscriptions for any products with available selling plans.
In this recipe you'll make the following changes:
- Set up a subscriptions app in your Shopify admin and add selling plans to any products that will be sold as subscriptions.
- Modify product detail pages to display subscription options with accurate pricing using the
SellingPlanSelector
component. - Enhance GraphQL fragments to fetch all necessary selling plan data.
- Display subscription details on applicable line items in the cart.
- Add a Subscriptions page where customers can manage their subscriptions, which includes the option to cancel active subscriptions.
Anchor to RequirementsRequirements
To implement subscriptions in your own store, you need to install a subscriptions app in your Shopify admin. In this recipe, we'll use the Shopify Subscriptions app.
Anchor to IngredientsIngredients
New files added to the template by this recipe.
File | Description |
---|---|
app/components/SellingPlanSelector.tsx | Displays the available subscription options on product pages. |
app/graphql/customer-account/CustomerSubscriptionsMutations.ts | Mutations for managing customer subscriptions. |
app/graphql/customer-account/CustomerSubscriptionsQuery.ts | Queries for managing customer subscriptions. |
app/routes/account.subscriptions.tsx | Subscriptions management page. |
app/styles/account-subscriptions.css | Subscriptions management page styles. |
app/styles/selling-plan.css | Styles the SellingPlanSelector component. |
Anchor to Step 1: Set up the Shopify Subscriptions appStep 1: Set up the Shopify Subscriptions app
- Install the Shopify Subscriptions app.
- In your Shopify admin, use the Subscriptions app to create one or more subscription plans.
- On the Products page, open any products that will be sold as subscriptions and add the relevant subscription plans in the Purchase options section.
The Hydrogen demo storefront comes pre-configured with an example subscription product with the handle
shopify-wax
.
Anchor to Step 2: Show subscription options on product pagesStep 2: Show subscription options on product pages
In this step we'll implement the ability to display subscription options on product pages, alongside the existing one-off purchase options.
Anchor to Step 2.1: Create a SellingPlanSelector componentStep 2. 1: Create a Selling Plan Selector component
Create a new SellingPlanSelector
component that displays the available subscription options for a product.
File
import type {
ProductFragment,
SellingPlanGroupFragment,
SellingPlanFragment,
} from 'storefrontapi.generated';
import {useMemo} from 'react';
import {useLocation} from 'react-router';
/* Enriched sellingPlan type including isSelected and url */
export type SellingPlan = SellingPlanFragment & {
isSelected: boolean;
url: string;
};
/* Enriched sellingPlanGroup type including enriched SellingPlan nodes */
export type SellingPlanGroup = Omit<
SellingPlanGroupFragment,
'sellingPlans'
> & {
sellingPlans: {
nodes: SellingPlan[];
};
};
/**
* A component that simplifies selecting sellingPlans subscription options
* @example Example use
*
**/
export function SellingPlanSelector({
sellingPlanGroups,
selectedSellingPlan,
children,
paramKey = 'selling_plan',
selectedVariant,
}: {
sellingPlanGroups: ProductFragment['sellingPlanGroups'];
selectedSellingPlan: SellingPlanFragment | null;
paramKey?: string;
selectedVariant: ProductFragment['selectedOrFirstAvailableVariant'];
children: (params: {
sellingPlanGroup: SellingPlanGroup;
selectedSellingPlan: SellingPlanFragment | null;
}) => React.ReactNode;
}) {
const {search, pathname} = useLocation();
const params = new URLSearchParams(search);
const planAllocationIds: string[] =
selectedVariant?.sellingPlanAllocations.nodes.map(
(node) => node.sellingPlan.id,
) ?? [];
return useMemo(
() =>
(sellingPlanGroups.nodes as SellingPlanGroup[])
// Filter out groups that don't have plans usable for the selected variant
.filter((group) => {
return group.sellingPlans.nodes.some((sellingPlan) =>
planAllocationIds.includes(sellingPlan.id),
);
})
.map((sellingPlanGroup) => {
// Augment each sellingPlan node with isSelected and url
const sellingPlans = sellingPlanGroup.sellingPlans.nodes
.map((sellingPlan: SellingPlan) => {
if (!sellingPlan?.id) {
console.warn(
'SellingPlanSelector: sellingPlan.id is missing in the product query',
);
return null;
}
if (!sellingPlan.id) {
return null;
}
params.set(paramKey, sellingPlan.id);
sellingPlan.isSelected =
selectedSellingPlan?.id === sellingPlan.id;
sellingPlan.url = `${pathname}?${params.toString()}`;
return sellingPlan;
})
.filter(Boolean) as SellingPlan[];
sellingPlanGroup.sellingPlans.nodes = sellingPlans;
return children({sellingPlanGroup, selectedSellingPlan});
}),
// eslint-disable-next-line react-hooks/exhaustive-deps
[
sellingPlanGroups,
children,
selectedSellingPlan,
paramKey,
pathname,
selectedVariant,
],
);
}
Anchor to Step 2.2: Add styles for the SellingPlanSelector componentStep 2. 2: Add styles for the Selling Plan Selector component
Add styles for the SellingPlanSelector
component.
File
Anchor to Step 2.3: Update ProductForm to support subscriptionsStep 2. 3: Update Product Form to support subscriptions
- Add conditional rendering to display subscription options alongside the standard variant selectors.
- Implement
SellingPlanSelector
andSellingPlanGroup
components to handle subscription plan selection. - Update
AddToCartButton
to include selling plan data when subscriptions are selected.
File
Anchor to Step 2.4: Update ProductPrice to display subscription pricingStep 2. 4: Update Product Price to display subscription pricing
- Add a
SellingPlanPrice
function to calculate adjusted prices based on subscription plan type (fixed amount, fixed price, or percentage). - Add logic to handle different price adjustment types and render the appropriate subscription price when a selling plan is selected.
File
Anchor to Step 2.5: Update the product page to display subscription optionsStep 2. 5: Update the product page to display subscription options
- Add the
SellingPlanSelector
component to display subscription options on product pages. - Add logic to handle pricing adjustments, maintain selection state using URL parameters, and update the add-to-cart functionality.
- Fetch subscription data through the updated cart GraphQL fragments.
File
Anchor to Step 3: Show subscription details in the cartStep 3: Show subscription details in the cart
In this step we'll implement support for showing subscription info in the cart's line items.
Anchor to Step 3.1: Add selling plan data to cart queriesStep 3. 1: Add selling plan data to cart queries
Add a sellingPlanAllocation
field with the plan name to the standard and componentizable cart line GraphQL fragments. This displays subscription details in the cart.
Anchor to Step 3.2: Render the selling plan in the cartStep 3. 2: Render the selling plan in the cart
- Update
CartLineItem
to show subscription details when they're available. - Extract
sellingPlanAllocation
from cart line data, display the plan name, and standardize component import paths.
Anchor to Step 4: Add subscription management to the account pageStep 4: Add subscription management to the account page
In this step we'll implement support for subscription management through an account subpage that lists existing subscription contracts.
Anchor to Step 4.1: Add queries to retrieve customer subscriptionsStep 4. 1: Add queries to retrieve customer subscriptions
Create GraphQL queries that retrieve the subscription info from the customer account client.
File
Anchor to Step 4.2: Add mutations to cancel customer subscriptionsStep 4. 2: Add mutations to cancel customer subscriptions
Create a GraqhQL mutation to cancel an existing subscription.
File
Anchor to Step 4.3: Add an account subscriptions pageStep 4. 3: Add an account subscriptions page
Create a new account subpage that lets customers manage their existing subscriptions based on the new GraphQL queries and mutations.
File
Add a Subscriptions
link to the account menu.
Anchor to Step 4.5: Add styles for the Subscriptions pageStep 4. 5: Add styles for the Subscriptions page
Add styles for the Subscriptions page.
File
Anchor to Next stepsNext steps
- Test your implementation by going to your store and adding a subscription-based product to the cart. Make sure that the product's subscription details appear on the product page and in the cart.
- (Optional) Place a test order to see how orders for subscription-based products appear in your Shopify admin.