Module Characteristics
The Magento_Shipping module has a notably minimal plugin footprint. It defines no plugins or observers internally. Instead, it relies heavily on:
- • DI preferences to swap implementations
- • Virtual types for logging configuration
- • Area-specific preferences (adminhtml vs global)
- • Extension by carrier modules (UPS, FedEx, etc.)
DI Preferences (Global)
Source: etc/di.xml
| Interface | Implementation | Purpose |
|---|---|---|
| Quote\Model\Quote\Address\ RateCollectorInterface |
Shipping\Model\Shipping | Main rate collection implementation |
| Shipping\Model\ CarrierFactoryInterface |
Shipping\Model\CarrierFactory | Creates carrier instances by code |
| Shipping\Model\Carrier\ Source\GenericInterface |
Shipping\Model\Carrier\ Source\GenericDefault |
Generic config source model |
DI Preferences (Admin Area)
Source: etc/adminhtml/di.xml
| Interface | Implementation | Purpose |
|---|---|---|
| Shipping\Model\Shipping | Shipping\Model\Shipping\Labels | Adds label generation capabilities in admin |
| Shipping\Model\ ShipmentProviderInterface |
Shipping\Model\ ShipmentProvider |
Provides current shipment in admin context |
Why Admin-Only Labels?
The Shipping\Labels class extends the base
Shipping class and adds
requestToShipment() functionality.
This is only available in the admin area because label generation requires
secure API credentials and should not be exposed to frontend code.
Virtual Types
The module defines virtual types for carrier-specific logging:
Carrier Debug Handler
<virtualType name="Magento\Shipping\Model\Carrier\VirtualDebug"
type="Magento\Framework\Logger\Handler\Base">
<arguments>
<argument name="fileName" xsi:type="string">
/var/log/shipping.log
</argument>
</arguments>
</virtualType>
Carrier Virtual Logger
<virtualType name="Magento\Shipping\Model\Method\VirtualLogger"
type="Magento\Framework\Logger\Monolog">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="debug" xsi:type="object">
Magento\Shipping\Model\Carrier\VirtualDebug
</item>
</argument>
</arguments>
</virtualType>
Logger Injection into Carriers
<type name="Magento\Shipping\Model\Carrier\AbstractCarrier">
<arguments>
<argument name="logger" xsi:type="object">
Magento\Shipping\Model\Method\VirtualLogger
</argument>
</arguments>
</type>
This configuration injects a specialized logger into all carrier classes that extends
AbstractCarrier. All carrier debug output goes to var/log/shipping.log.
Type Argument Configuration
Source: etc/adminhtml/di.xml
<type name="Magento\Shipping\Helper\Data">
<arguments>
<!-- Use frontend URL model in admin context -->
<argument name="url" xsi:type="object">
Magento\Framework\Url
</argument>
</arguments>
</type>
The Helper\Data class is injected with the frontend URL model even in admin context. This ensures tracking URLs generated in admin emails point to the frontend store.
Plugins Targeting Shipping Classes
While Magento_Shipping defines no plugins itself, other modules extend its functionality:
| Source Module | Target Class | Plugin Purpose |
|---|---|---|
| Magento_Ups | Block\DataProviders\ Tracking\DeliveryDateTitle |
Updates delivery date title for UPS tracking |
| Magento_Fedex | Block\DataProviders\ Tracking\DeliveryDateTitle |
Updates delivery date title for FedEx tracking |
| Magento_Fedex | Block\Tracking\Popup | Updates delivery date value for FedEx |
| Magento_Inventory ShippingAdminUi |
Block\Adminhtml\Create | Modifies back button URL for MSI |
| Magento_InventoryIn StorePickupShippingAdminUi |
Controller\Adminhtml\ Order\Shipment\View |
Adds store pickup tracking info |
| Magento_InventoryIn StorePickupShippingAdminUi |
Block\Adminhtml\View | Adds store pickup tracking button |
Preferences Overriding Shipping Classes
| Source Module | Original Class | Replacement Class |
|---|---|---|
| Magento_Inventory Shipping |
Controller\Adminhtml\ Order\Shipment\NewAction |
InventoryShipping\ Controller\...\NewAction |
MSI Override: When Multi-Source Inventory is enabled, the shipment creation controller is replaced to support source selection during shipping.
Cron Configuration
Source: etc/crontab.xml
<config>
<group id="default">
<job name="aggregate_sales_report_shipment_data"
instance="Magento\Shipping\Model\Observer"
method="aggregateSalesReportShipmentData">
<schedule>0 0 * * *</schedule>
</job>
</group>
</config>
| Job Name | Schedule | Purpose |
|---|---|---|
| aggregate_sales_report_ shipment_data |
0 0 * * * (midnight daily) | Aggregates shipment data for sales reports |
ACL Configuration
Source: etc/acl.xml
<acl>
<resources>
<resource id="Magento_Backend::admin">
<resource id="Magento_Backend::stores">
<resource id="Magento_Backend::stores_settings">
<resource id="Magento_Config::config">
<resource id="Magento_Shipping::config_shipping"
title="Shipping Settings"
sortOrder="30" />
<resource id="Magento_Shipping::carriers"
title="Shipping Methods"
sortOrder="40" />
</resource>
</resource>
</resource>
</resource>
</resources>
</acl>
config_shipping
Controls access to Shipping Settings (origin address, policy)
carriers
Controls access to Shipping Methods configuration
Extension Best Practices
DO
- ✔ Create new carriers by extending AbstractCarrier or AbstractCarrierOnline
- ✔ Register carriers via config.xml under carriers/[code]/model
- ✔ Use plugins on Block\DataProviders classes for tracking customization
- ✔ Log carrier debug output using $this->_debug($debugData)
- ✔ Return proper Error objects when carrier is unavailable
DON'T
- ✖ Override the Shipping class with a preference (use plugins instead)
- ✖ Modify carrier factory directly (register carriers via config)
- ✖ Skip validation in collectRates() (always check country/weight limits)
- ✖ Return null from collectRates() without explanation
- ✖ Store API credentials in code (use encrypted config)