Pickup Options
Overview
Pickup options use a group → stores model. Each group is tied to a shipping method and holds a list of pickup store entries, allowing multiple pickup providers to appear side-by-side.
When Amasty StorePickup With Locator is active, the built-in integration populates locations
automatically, records the chosen store on submission, and marks the shipping option as
LOCAL_PICKUP. No custom observers are required for Amasty.
Custom observers can add groups, modify stores within existing groups, or remove groups entirely.
All observers share the same mutable groups object and are dispatched in registration order.
Adding a custom pickup group
Listen to simpler_checkout_pickup_options_requested. The event data exposes a groups
object; add a group with a shippingId matching your carrier code, a strategy, and one or more
store entries. See Strategies and Data model for property details.
namespace MyModule\Pickup\Observer;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Simpler\Checkout\Api\Data\PickupOptionsGroupInterfaceFactory;
use Simpler\Checkout\Api\Data\PickupOptionsStoreInterfaceFactory;
class AddCustomPickupGroup implements ObserverInterface
{
private PickupOptionsGroupInterfaceFactory $groupFactory;
private PickupOptionsStoreInterfaceFactory $storeFactory;
public function __construct(
PickupOptionsGroupInterfaceFactory $groupFactory,
PickupOptionsStoreInterfaceFactory $storeFactory
) {
$this->groupFactory = $groupFactory;
$this->storeFactory = $storeFactory;
}
public function execute(Observer $observer): void
{
/** @var \Simpler\Checkout\Api\Data\PickupOptionsGroupsInterface $groups */
$groups = $observer->getData('groups');
$group = $this->groupFactory->create();
$group->setShippingId('mycustom_pickup');
$group->setTitle('My Pickup Points');
$group->setStrategy('expand');
$store = $this->storeFactory->create();
$store->setId('store_athens_01');
$store->setTitle('Athens Central');
$store->setCountryCodes(['GR']);
$group->addStore($store);
$groups->addGroup($group);
}
}
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="simpler_checkout_pickup_options_requested">
<observer name="my_custom_pickup_group"
instance="MyModule\Pickup\Observer\AddCustomPickupGroup"
shared="true" />
</event>
</config>
Marking a shipping option as LOCAL_PICKUP
Listen to simpler_checkout_around_create_shipping_option and call
$option->setType('LOCAL_PICKUP') for your carrier. This is required for Simpler to render the
option with pickup-specific UI.
namespace MyModule\Pickup\Observer;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
class MarkAsLocalPickup implements ObserverInterface
{
public function execute(Observer $observer): void
{
$method = $observer->getData('shipping_method');
$option = $observer->getData('shipping_option');
if ($method->getCarrierCode() === 'mycustom_pickup') {
$option->setType('LOCAL_PICKUP');
}
}
}
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="simpler_checkout_around_create_shipping_option">
<observer name="my_carrier_mark_shipping_option_as_local_pickup"
instance="MyModule\Pickup\Observer\MarkAsLocalPickup"
shared="true" />
</event>
</config>
Persisting the chosen location on submit
Simpler includes the chosen store's id in the submit payload as pickup_store_id on the
shipping address. Read it in an observer and persist it however your module requires.
| Event | When | Data |
|---|---|---|
simpler_checkout_after_shipping_method_selected | After shipping is applied, before payment | quote, store_id, request |
simpler_checkout_before_order_placed | After payment, immediately before placeOrder() | quote, request |
Use simpler_checkout_before_order_placed unless you need to modify the quote (e.g. adjust
totals) before payment is recorded.
namespace MyModule\Pickup\Observer;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\ObjectManagerInterface;
class SetPickupStoreId implements ObserverInterface
{
private ObjectManagerInterface $objectManager;
public function __construct(ObjectManagerInterface $objectManager)
{
$this->objectManager = $objectManager;
}
public function execute(Observer $observer): void
{
/** @var \Simpler\Checkout\Api\Data\SubmitRequestInterface $request */
$request = $observer->getData('request');
$storeId = $request->getShippingTo()?->getPickupStoreId();
if (empty($storeId)) {
return;
}
/** @var \Magento\Quote\Model\Quote $quote */
$quote = $observer->getData('quote');
if ($quote->getShippingAddress()->getShippingMethod() !== 'mycustom_pickup') {
return;
}
$myRepository = $this->objectManager->get(\MyModule\Pickup\Model\QuoteRepository::class);
$myQuote = $myRepository->getByQuoteId($quote->getId());
$myQuote->setPickupLocationId((int) $storeId);
$myRepository->save($myQuote);
}
}
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="simpler_checkout_before_order_placed">
<observer name="my_custom_pickup_set_store_id"
instance="MyModule\Pickup\Observer\SetPickupStoreId"
shared="false" />
</event>
</config>
Advanced: modifying or suppressing groups
Later observers see everything earlier observers added. Use this to suppress, filter, or rename groups added by built-in or third-party observers.
Suppress the Amasty group
public function execute(Observer $observer): void
{
$groups = $observer->getData('groups');
$groups->setGroups(array_values(array_filter(
$groups->getGroups(),
fn($g) => $g->getShippingId() !== 'amstorepickup_amstorepickup'
)));
}
Filter stores by country
public function execute(Observer $observer): void
{
$groups = $observer->getData('groups');
foreach ($groups->getGroups() as $group) {
if ($group->getShippingId() === 'amstorepickup_amstorepickup') {
$group->setStores(array_values(array_filter(
$group->getStores(),
fn($s) => in_array('GR', $s->getCountryCodes() ?? [])
)));
}
}
}
Rename the Amasty group
Register this observer after the built-in one so the group already exists when it runs.
public function execute(Observer $observer): void
{
$groups = $observer->getData('groups');
foreach ($groups->getGroups() as $group) {
if ($group->getShippingId() === 'amstorepickup_amstorepickup') {
$group->setTitle('Click & Collect');
break;
}
}
}
Reference
Strategies
append — Stores appear as standalone shipping options regardless of carrier quotes.
The selected store is submitted as the shipping method ID. Use for locker and parcel-shop networks.
merge — The group is shown only when a matching carrier quote exists. The selected store
is submitted as the shipping method ID.
expand — Like merge, but Simpler also sends a separate pickup_store_id field alongside
the shipping method ID. Use when the backend needs the store ID as a distinct value (e.g. Amasty).
Data model
PickupOptionsGroupsInterface
getGroups(): array — All currently registered groups.
addGroup(PickupOptionsGroupInterface $group): self — Appends a group.
setGroups(array $groups): self — Replaces the entire groups array.
PickupOptionsGroupInterface
getShippingId() / setShippingId(?string $id) — Magento carrier code. Groups whose method
is absent from the cart are silently ignored.
getTitle() / setTitle(?string $title) — Display title shown in Simpler Checkout.
getStrategy() / setStrategy(string $strategy) — 'append', 'merge', or 'expand'.
See Strategies.
getStores() / setStores(array $stores) — Full store list for this group.
addStore(PickupOptionsStoreInterface $store): self — Appends a single store.
PickupOptionsStoreInterface
getId() / setId(string $id) — Unique store identifier.
getTitle() / setTitle(string $title) — Store display name.
getCountryCodes() / setCountryCodes(?array $codes) — ISO 3166-1 alpha-2 codes. Pass null
to show the store to all countries.
getStoreIds() / setStoreIds(?array $ids) — Magento store-view IDs. Pass null to show on
all store-views.