Eigene Versandarten in Magento 2: Grundlagen
Eigene Versandarten in Magento 2: Grundlagen
~6 Min. Lesezeit Zuletzt aktualisiert am 9. August 2026
Kapitel 62-65 haben eine Zahlungsart Schritt für Schritt über eine moderne, komponierte Adapter-Facade gebaut. Versandarten ("Carrier" in Magentos eigener Terminologie) laufen technisch anders - näher am alten AbstractMethod-Weg aus Kapitel 62, aber mit eigenen Besonderheiten.
AbstractCarrier und CarrierInterface
Jede Versandart erbt von Magento\Shipping\Model\Carrier\AbstractCarrier und implementiert CarrierInterface - bis Magento 2.4.8 gibt es dafür kein Adapter-Facade-Pendant wie bei Zahlungsarten. Der Methodencode lebt weiterhin in einer klassischen protected-Property ($_code), nicht in einer per di.xml-const-Argument injizierten Konstante. Zwei Methoden sind Pflicht:
- collectRates(RateRequest $request) - die eigentliche Kalkulation, liefert entweder ein befülltes
Magento\Shipping\Model\Rate\Result-Objekt (Kapitel 68) oderfalse, wenn die Versandart für diese Anfrage nicht infrage kommt. - getAllowedMethods() - ein assoziatives Array aller von diesem Carrier angebotenen Methodencodes, u. a. von der Admin-Konfigurationsseite und Vergleichs-Tools wie Table Rate genutzt, unabhängig davon, ob
collectRates()im konkreten Request überhaupt etwas zurückliefert.
<?php
declare(strict_types=1);
namespace Mironsoft\Loyalty\Model\Carrier;
use Magento\Quote\Model\Quote\Address\RateRequest;
use Magento\Shipping\Model\Carrier\AbstractCarrier;
use Magento\Shipping\Model\Carrier\CarrierInterface;
use Magento\Shipping\Model\Rate\Result;
/**
* Skeleton only - chapter 67 fills in the business logic. Note the carrier code
* lives in a plain protected property, not a class constant fed through di.xml
* like the payment facade in chapter 62: shipping carriers have no Adapter-style
* facade equivalent, even in Magento 2.4.8 - AbstractCarrier is still the only,
* property-based way in.
*/
class FreeShippingByPoints extends AbstractCarrier implements CarrierInterface
{
/**
* Carrier code, referenced by carriers/mironsoft_loyalty_freeshipping/* config paths.
*/
protected $_code = 'mironsoft_loyalty_freeshipping';
/**
* Calculates shipping rates for the given request. Required by CarrierInterface.
*
* @param RateRequest $request Shipping rate request
* @return Result|bool
*/
public function collectRates(RateRequest $request)
{
// see chapter 67
}
/**
* Returns the codes and titles of all shipping methods this carrier can offer.
* Required by AbstractCarrier, used e.g. by the admin's "Applicable Countries"
* comparison tooling.
*
* @return string[]
*/
public function getAllowedMethods(): array
{
return ['freeshipping' => $this->getConfigData('name')];
}
}
Registrierung über das model-Feld in config.xml
Genau wie bei der Zahlungsart aus Kapitel 62 bestimmt kein di.xml-virtualType, welche Klasse für einen Carrier-Code instanziiert wird, sondern ein model-Konfigurationswert unter carriers/<code>/model in etc/config.xml - dieselbe Registrierungs-Idee, nur unter einem anderen Config-Wurzelknoten (carriers statt payment):
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
<default>
<carriers>
<mironsoft_loyalty_freeshipping>
<active>0</active>
<model>Mironsoft\Loyalty\Model\Carrier\FreeShippingByPoints</model>
<name>Kostenloser Versand durch Punkte</name>
<title>Mironsoft Loyalty</title>
<points_cost>200</points_cost>
<sallowspecific>0</sallowspecific>
<sort_order>10</sort_order>
</mironsoft_loyalty_freeshipping>
</carriers>
</default>
</config>
Tipp: Magento\Shipping\Model\Config::getActiveCarriers() liest genau diese carriers/*/active- und carriers/*/model-Werte aus und instanziiert jeden aktiven Carrier über den ObjectManager - konzeptionell derselbe Mechanismus wie Magento\Payment\Helper\Data::getMethodInstance() bei Zahlungsarten, nur ohne den zusätzlichen Adapter/ValueHandlerPool-Umweg aus Kapitel 62.
Achtung: sallowspecific und specificcountry sind keine kosmetischen Zusatzfelder - sie steuern, ob eine Versandart überhaupt an bestimmte Länder liefern darf, und werden von AbstractCarrier::checkAvailableShipCountries() ausgewertet. Fehlen sie in system.xml (Kapitel 67), lässt sich die Länderbeschränkung im Admin schlicht nicht konfigurieren, auch wenn der PHP-Code sie später korrekt auswertet.
Mit Grundlagen und Registrierung geklärt, baut Kapitel 67 die eigentliche Geschäftslogik: kostenloser Versand, freigeschaltet durch ausreichend Treuepunkte.