Buy online, pickup in store
Buy online, pickup in store (BOPIS) is a popular fulfillment option that allows customers to purchase items online and pick them up in-store.
The Commerce boilerplate template does not include a BOPIS checkout flow by default, but you can easily implement one using Adobe’s drop-in components.
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
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
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__delivery-method"><h2 class="checkout-delivery-method__title">Delivery Method</h2><div class="checkout-delivery-method__toogle-buttons"><div class="checkout-delivery-method__delivery-button"></div><div class="checkout-delivery-method__in-store-pickup-button"></div></div></div><div class="checkout__in-store-pickup"></div>You must also add new selectors to render the required components and content.
export const $deliveryButton = fragment.querySelector('.checkout-delivery-method__delivery-button');export const $inStorePickupButton = fragment.querySelector('.checkout-delivery-method__in-store-pickup-button');export const $inStorePickup = fragment.querySelector('.checkout__in-store-pickup');
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
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'); $shippingMethods.removeAttribute('hidden'); $inStorePickup.setAttribute('hidden', ''); } else { inStorePickupButton.setProps((prev) => ({ ...prev, selected: true })); deliveryButton.setProps((prev) => ({ ...prev, selected: false })); $shippingForm.setAttribute('hidden', ''); $shippingMethods.setAttribute('hidden', ''); $inStorePickup.removeAttribute('hidden'); }}
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
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, value: name, onChange: () => { checkoutApi.setShippingAddress({ address: {}, pickupLocationCode: pickup_location_code, }); }, })(locationRadiobutton);
$inStorePickup.appendChild(locationRadiobutton);});
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.
Example
See blocks/commerce-checkout-bopis
in the demos
branch of the boilerplate repository for complete JS and CSS code for the BOPIS checkout flow.