Buy online, pickup in store
Buy online, pickup in store (BOPIS) lets shoppers buy items on your storefront and pick them up in person. The Commerce boilerplate doesn’t include a BOPIS checkout flow by default, but this tutorial shows you how to add one with Adobe’s drop-in components.
What you’ll edit or create
Section titled “What you’ll edit or create”- Edit the checkout block —
blocks/commerce-checkout/commerce-checkout.js - Edit the
ToggleButtoncomponent - Edit the
RadioButtoncomponent - Create the
fetchPickupLocations()function
What you’ll build
Section titled “What you’ll build”By the end of this tutorial, you’ll have:
- Delivery and in-store pickup toggle buttons added to the
commerce-checkout.jsblock file using theToggleButtoncomponent. - A list of pickup locations fetched from Adobe Commerce and rendered as
RadioButtonoptions. - The shipping address updated with the selected pickup location code when a shopper chooses in-store pickup.
Step-by-step
Section titled “Step-by-step”The following steps describe how to modify the commerce-checkout.js block file in the boilerplate template to allow users to choose between delivery and in-store pickup during the checkout process.
Prerequisites
Section titled “Prerequisites”Before you start, you must configure in-store delivery options in the Adobe Commerce Admin to define pickup locations. The fetchPickupLocations function retrieves the list of available pickup locations using a GraphQL query.
Update content fragment
Section titled “Update content fragment”-
To create a new section for the delivery options, additional DOM elements are required. You can add these elements by modifying the content fragment.
<div class="checkout__block checkout__delivery-method"><h2 class="checkout__block checkout-delivery-method__title">Delivery Method</h2><div class="checkout__block checkout-delivery-method__toggle-buttons"><div class="checkout__block checkout-delivery-method__delivery-button"></div><div class="checkout__block checkout-delivery-method__in-store-pickup-button"></div></div></div><div class="checkout__block checkout__in-store-pickup"></div> -
You must also add new selectors to render the required components and content.
const $deliveryButton = checkoutFragment.querySelector('.checkout-delivery-method__delivery-button');const $inStorePickupButton = checkoutFragment.querySelector('. checkout-delivery-method__in-store-pickup-button');const $inStorePickup = checkoutFragment.querySelector('.checkout__in-store-pickup');
Add toggle buttons
Section titled “Add toggle buttons”During initialization, the code renders two buttons:
- Delivery
- In-store pickup
These buttons allow users to toggle between the two options.
UI.render(ToggleButton, { label: 'Delivery', onChange: () => onToggle('delivery'),})($deliveryButton),
UI.render(ToggleButton, { label: 'In-store Pickup', onChange: () => onToggle('in-store-pickup'),})($inStorePickupButton),
Toggle between options
Section titled “Toggle between options”The onToggle function manages switching between the delivery and in-store pickup options. It updates the selected state of the buttons and toggles the visibility of the corresponding forms.
async function onToggle(type) { if (type === 'delivery') { deliveryButton.setProps((prev) => ({ ...prev, selected: true })); inStorePickupButton.setProps((prev) => ({ ...prev, selected: false })); $shippingForm.removeAttribute('hidden'); $delivery.removeAttribute('hidden'); $inStorePickup.setAttribute('hidden', ''); } else { inStorePickupButton.setProps((prev) => ({ ...prev, selected: true })); deliveryButton.setProps((prev) => ({ ...prev, selected: false })); $shippingForm.setAttribute('hidden', ''); $delivery.setAttribute('hidden', ''); $inStorePickup.removeAttribute('hidden'); }}Fetch pickup locations
Section titled “Fetch pickup locations”The fetchPickupLocations function retrieves the list of available pickup locations using a GraphQL query. Users can choose a location where they’d like to pick up their order.
async function fetchPickupLocations() { return checkoutApi .fetchGraphQl( `query pickupLocations { pickupLocations { items { name pickup_location_code } total_count } }`, { method: 'GET', cache: 'no-cache' } ) .then((res) => res.data.pickupLocations.items);}Render location options
Section titled “Render location options”After the code fetches the pickup locations, it renders options as radio buttons. The user can select a location, which updates the shipping address with the corresponding pickup location code.
const pickupLocations = await fetchPickupLocations();
pickupLocations.forEach((location) => { const { name, pickup_location_code } = location; const locationRadiobutton = document.createElement('div');
UI.render(RadioButton, { label: name, name: 'pickup-location', value: name, onChange: () => { checkoutApi.setShippingAddress({ address: {}, pickupLocationCode: pickup_location_code, }); }, })(locationRadiobutton);
$inStorePickup.appendChild(locationRadiobutton);});
Finalize the flow
Section titled “Finalize the flow”After a user selects In-store pickup and chooses a location, the pickup form is shown, while the shipping form is hidden. This provides a clear and seamless way for users to choose how they want to receive their order.
Related
Section titled “Related”- Checkout overview — where in-store pickup fits in the flow.
- ShippingMethods container — reference for the delivery options you extended.