Skip to main content

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.

src/Observer/AddCustomPickupGroup.php
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);
}
}
src/etc/events.xml
<?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.

src/Observer/MarkAsLocalPickup.php
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');
}
}
}
src/etc/events.xml
<?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.

EventWhenData
simpler_checkout_after_shipping_method_selectedAfter shipping is applied, before paymentquote, store_id, request
simpler_checkout_before_order_placedAfter 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.

src/Observer/SetPickupStoreId.php
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);
}
}
src/etc/events.xml
<?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

src/Observer/SuppressAmastyPickupGroup.php
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

src/Observer/FilterAmastyPickupByCountry.php
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.

src/Observer/RenameAmastyPickupGroup.php
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.