shipping-method-development
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseShipping Method Development
配送方式开发
Overview
概述
Creating custom shipping methods in Bagisto allows you to tailor delivery options to meet your specific business needs. Whether you need special handling for fragile items, express delivery options, or region-specific shipping rules, custom shipping methods provide the flexibility your e-commerce store requires.
For our tutorial, we'll create a Custom Express Shipping method that demonstrates all the essential concepts you need to build any type of shipping solution.
在Bagisto中创建自定义配送方式,可让您量身定制配送选项以满足特定业务需求。无论您需要对易碎物品进行特殊处理、提供加急配送选项,还是设置特定地区的配送规则,自定义配送方式都能为您的电商店铺提供所需的灵活性。
在本教程中,我们将创建一个自定义加急配送方式,演示构建任何类型配送解决方案所需的所有核心概念。
When to Apply
适用场景
Activate this skill when:
- Creating new shipping methods
- Integrating shipping carriers (FedEx, UPS, DHL, USPS, etc.)
- Adding shipping options to checkout
- Modifying existing shipping configurations
- Creating admin configuration for shipping methods
- Implementing rate calculation logic
在以下场景中启用本技能:
- 创建新的配送方式
- 集成配送承运商(FedEx、UPS、DHL、USPS等)
- 在结账环节添加配送选项
- 修改现有配送配置
- 为配送方式创建后台管理配置
- 实现费率计算逻辑
Bagisto Shipping Architecture
Bagisto配送架构
Bagisto's shipping system is built around a flexible carrier-based architecture that separates configuration from business logic.
Bagisto的配送系统基于灵活的承运商架构构建,将配置与业务逻辑分离。
Core Components
核心组件
| Component | Purpose | Location |
|---|---|---|
| Carriers Configuration | Defines shipping method properties | |
| Carrier Classes | Contains rate calculation logic | |
| System Configuration | Admin interface forms | |
| Service Provider | Registers shipping method | |
| Shipping Facade | Collects and manages rates | |
| 组件 | 用途 | 位置 |
|---|---|---|
| 承运商配置 | 定义配送方式属性 | |
| 承运商类 | 包含费率计算逻辑 | |
| 系统配置 | 后台管理界面表单 | |
| 服务提供者 | 注册配送方式 | |
| Shipping Facade | 收集和管理费率 | |
Key Features
关键特性
- Flexible Rate Calculation: Support for per-unit, per-order, weight-based, or custom pricing.
- Configuration Management: Admin-friendly settings interface.
- Multi-channel Support: Different rates and settings per sales channel.
- Localization Ready: Full translation support.
- Extensible Architecture: Easy integration with third-party APIs.
- 灵活的费率计算:支持按单位、按订单、按重量或自定义定价。
- 配置管理:便于后台操作的设置界面。
- 多渠道支持:每个销售渠道可设置不同的费率和配置。
- 本地化就绪:完整的翻译支持。
- 可扩展架构:轻松集成第三方API。
Step-by-Step Guide
分步指南
Step 1: Create Package Directory Structure
步骤1:创建包目录结构
bash
mkdir -p packages/Webkul/CustomExpressShipping/src/{Carriers,Config,Providers}bash
mkdir -p packages/Webkul/CustomExpressShipping/src/{Carriers,Config,Providers}Step 2: Create Carrier Configuration
步骤2:创建承运商配置
File:
packages/Webkul/CustomExpressShipping/src/Config/carriers.phpphp
<?php
return [
'custom_express_shipping' => [
'code' => 'custom_express_shipping',
'title' => 'Express Delivery (1-2 Days)',
'description' => 'Premium express shipping with tracking',
'active' => true,
'default_rate' => '19.99',
'type' => 'per_order',
'class' => 'Webkul\CustomExpressShipping\Carriers\CustomExpressShipping',
],
];文件位置:
packages/Webkul/CustomExpressShipping/src/Config/carriers.phpphp
<?php
return [
'custom_express_shipping' => [
'code' => 'custom_express_shipping',
'title' => 'Express Delivery (1-2 Days)',
'description' => 'Premium express shipping with tracking',
'active' => true,
'default_rate' => '19.99',
'type' => 'per_order',
'class' => 'Webkul\CustomExpressShipping\Carriers\CustomExpressShipping',
],
];Configuration Properties Explained
配置属性说明
| Property | Type | Purpose | Description |
|---|---|---|---|
| String | Unique identifier | Must match the array key and |
| String | Default display name | Shown to customers during checkout (can be overridden in admin). |
| String | Method description | Brief explanation of the shipping service. |
| Boolean | Default status | Whether the shipping method is enabled by default. |
| String/Float | Base shipping cost | Base shipping cost before calculations. |
| String | Pricing model | |
| String | Carrier class namespace | Full path to your carrier class. |
Note: The array key () must match thecustom_express_shippingproperty in your carrier class, system configuration key path, and should be consistent throughout.code
| 属性 | 类型 | 用途 | 描述 |
|---|---|---|---|
| 字符串 | 唯一标识符 | 必须与数组键以及承运商类中的 |
| 字符串 | 默认显示名称 | 在结账环节向客户展示(可在后台管理中修改)。 |
| 字符串 | 方式描述 | 配送服务的简要说明。 |
| 布尔值 | 默认状态 | 配送方式是否默认启用。 |
| 字符串/浮点数 | 基础配送成本 | 计算前的基础配送费用。 |
| 字符串 | 定价模式 | |
| 字符串 | 承运商类命名空间 | 承运商类的完整路径。 |
注意: 数组键()必须与承运商类中的custom_express_shipping属性、系统配置键路径保持一致,并在整个开发过程中统一。$code
Step 3: Create Carrier Class
步骤3:创建承运商类
File:
packages/Webkul/CustomExpressShipping/src/Carriers/CustomExpressShipping.phpphp
<?php
namespace Webkul\CustomExpressShipping\Carriers;
use Webkul\Shipping\Carriers\AbstractShipping;
use Webkul\Checkout\Models\CartShippingRate;
use Webkul\Checkout\Facades\Cart;
class CustomExpressShipping extends AbstractShipping
{
/**
* Shipping method code - must match carriers.php key.
*
* @var string
*/
protected $code = 'custom_express_shipping';
/**
* Shipping method code.
*
* @var string
*/
protected $method = 'custom_express_shipping_custom_express_shipping';
/**
* Calculate shipping rate for the current cart.
*
* @return \Webkul\Checkout\Models\CartShippingRate|false
*/
public function calculate()
{
if (! $this->isAvailable()) {
return false;
}
return $this->getRate();
}
/**
* Get shipping rate.
*
* @return \Webkul\Checkout\Models\CartShippingRate
*/
public function getRate(): CartShippingRate
{
$cart = Cart::getCart();
$cartShippingRate = new CartShippingRate;
$cartShippingRate->carrier = $this->getCode();
$cartShippingRate->carrier_title = $this->getConfigData('title');
$cartShippingRate->method = $this->getMethod();
$cartShippingRate->method_title = $this->getConfigData('title');
$cartShippingRate->method_description = $this->getConfigData('description');
$cartShippingRate->price = 0;
$cartShippingRate->base_price = 0;
$baseRate = (float) $this->getConfigData('default_rate');
if ($this->getConfigData('type') == 'per_unit') {
foreach ($cart->items as $item) {
if ($item->getTypeInstance()->isStockable()) {
$cartShippingRate->price += core()->convertPrice($baseRate) * $item->quantity;
$cartShippingRate->base_price += $baseRate * $item->quantity;
}
}
} else {
$cartShippingRate->price = core()->convertPrice($baseRate);
$cartShippingRate->base_price = $baseRate;
}
return $cartShippingRate;
}
}文件位置:
packages/Webkul/CustomExpressShipping/src/Carriers/CustomExpressShipping.phpphp
<?php
namespace Webkul\CustomExpressShipping\Carriers;
use Webkul\Shipping\Carriers\AbstractShipping;
use Webkul\Checkout\Models\CartShippingRate;
use Webkul\Checkout\Facades\Cart;
class CustomExpressShipping extends AbstractShipping
{
/**
* Shipping method code - must match carriers.php key.
*
* @var string
*/
protected $code = 'custom_express_shipping';
/**
* Shipping method code.
*
* @var string
*/
protected $method = 'custom_express_shipping_custom_express_shipping';
/**
* Calculate shipping rate for the current cart.
*
* @return \Webkul\Checkout\Models\CartShippingRate|false
*/
public function calculate()
{
if (! $this->isAvailable()) {
return false;
}
return $this->getRate();
}
/**
* Get shipping rate.
*
* @return \Webkul\Checkout\Models\CartShippingRate
*/
public function getRate(): CartShippingRate
{
$cart = Cart::getCart();
$cartShippingRate = new CartShippingRate;
$cartShippingRate->carrier = $this->getCode();
$cartShippingRate->carrier_title = $this->getConfigData('title');
$cartShippingRate->method = $this->getMethod();
$cartShippingRate->method_title = $this->getConfigData('title');
$cartShippingRate->method_description = $this->getConfigData('description');
$cartShippingRate->price = 0;
$cartShippingRate->base_price = 0;
$baseRate = (float) $this->getConfigData('default_rate');
if ($this->getConfigData('type') == 'per_unit') {
foreach ($cart->items as $item) {
if ($item->getTypeInstance()->isStockable()) {
$cartShippingRate->price += core()->convertPrice($baseRate) * $item->quantity;
$cartShippingRate->base_price += $baseRate * $item->quantity;
}
}
} else {
$cartShippingRate->price = core()->convertPrice($baseRate);
$cartShippingRate->base_price = $baseRate;
}
return $cartShippingRate;
}
}Step 4: Create System Configuration
步骤4:创建系统配置
File:
packages/Webkul/CustomExpressShipping/src/Config/system.phpphp
<?php
return [
[
'key' => 'sales.carriers.custom_express_shipping',
'name' => 'Custom Express Shipping',
'info' => 'Configure the Custom Express Shipping method settings.',
'sort' => 1,
'fields' => [
[
'name' => 'title',
'title' => 'Method Title',
'type' => 'text',
'validation' => 'required',
'channel_based' => true,
'locale_based' => true,
],
[
'name' => 'description',
'title' => 'Description',
'type' => 'textarea',
'channel_based' => true,
'locale_based' => false,
],
[
'name' => 'default_rate',
'title' => 'Base Rate',
'type' => 'text',
'validation' => 'required|numeric|min:0',
'channel_based' => true,
'locale_based' => false,
],
[
'name' => 'type',
'title' => 'Pricing Type',
'type' => 'select',
'options' => [
[
'title' => 'Per Order (Flat Rate)',
'value' => 'per_order',
],
[
'title' => 'Per Item',
'value' => 'per_unit',
],
],
'channel_based' => true,
'locale_based' => false,
],
[
'name' => 'active',
'title' => 'Enabled',
'type' => 'boolean',
'validation' => 'required',
'channel_based' => true,
'locale_based' => false,
],
],
],
];文件位置:
packages/Webkul/CustomExpressShipping/src/Config/system.phpphp
<?php
return [
[
'key' => 'sales.carriers.custom_express_shipping',
'name' => 'Custom Express Shipping',
'info' => 'Configure the Custom Express Shipping method settings.',
'sort' => 1,
'fields' => [
[
'name' => 'title',
'title' => 'Method Title',
'type' => 'text',
'validation' => 'required',
'channel_based' => true,
'locale_based' => true,
],
[
'name' => 'description',
'title' => 'Description',
'type' => 'textarea',
'channel_based' => true,
'locale_based' => false,
],
[
'name' => 'default_rate',
'title' => 'Base Rate',
'type' => 'text',
'validation' => 'required|numeric|min:0',
'channel_based' => true,
'locale_based' => false,
],
[
'name' => 'type',
'title' => 'Pricing Type',
'type' => 'select',
'options' => [
[
'title' => 'Per Order (Flat Rate)',
'value' => 'per_order',
],
[
'title' => 'Per Item',
'value' => 'per_unit',
],
],
'channel_based' => true,
'locale_based' => false,
],
[
'name' => 'active',
'title' => 'Enabled',
'type' => 'boolean',
'validation' => 'required',
'channel_based' => true,
'locale_based' => false,
],
],
],
];System Configuration Field Properties
系统配置字段属性
| Property | Purpose | Description |
|---|---|---|
| Field identifier | Used to store and retrieve configuration values. |
| Field label | Label displayed in the admin form. |
| Input type | |
| Default setting | Initial value when first configured. |
| Multi-store support | Different values per sales channel. |
| Multi-language support | Translatable content per language. |
| Field validation | Rules like |
| 属性 | 用途 | 描述 |
|---|---|---|
| 字段标识符 | 用于存储和检索配置值。 |
| 字段标签 | 在后台表单中显示的标签。 |
| 输入类型 | |
| 默认设置 | 首次配置时的初始值。 |
| 多店铺支持 | 每个销售渠道可设置不同的值。 |
| 多语言支持 | 每种语言可设置不同的可翻译内容。 |
| 字段验证 | 验证规则,如 |
Step 5: Create Service Provider
步骤5:创建服务提供者
File:
packages/Webkul/CustomExpressShipping/src/Providers/CustomExpressShippingServiceProvider.phpphp
<?php
namespace Webkul\CustomExpressShipping\Providers;
use Illuminate\Support\ServiceProvider;
class CustomExpressShippingServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register(): void
{
$this->mergeConfigFrom(
dirname(__DIR__) . '/Config/carriers.php',
'carriers'
);
$this->mergeConfigFrom(
dirname(__DIR__) . '/Config/system.php',
'core'
);
}
/**
* Bootstrap services.
*
* @return void
*/
public function boot(): void
{
//
}
}文件位置:
packages/Webkul/CustomExpressShipping/src/Providers/CustomExpressShippingServiceProvider.phpphp
<?php
namespace Webkul\CustomExpressShipping\Providers;
use Illuminate\Support\ServiceProvider;
class CustomExpressShippingServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register(): void
{
$this->mergeConfigFrom(
dirname(__DIR__) . '/Config/carriers.php',
'carriers'
);
$this->mergeConfigFrom(
dirname(__DIR__) . '/Config/system.php',
'core'
);
}
/**
* Bootstrap services.
*
* @return void
*/
public function boot(): void
{
//
}
}Step 6: Register Your Package
步骤6:注册您的包
- Add to composer.json (in Bagisto root directory):
json
{
"autoload": {
"psr-4": {
"Webkul\\CustomExpressShipping\\": "packages/Webkul/CustomExpressShipping/src"
}
}
}- Update autoloader:
bash
composer dump-autoload- Register service provider in :
bootstrap/providers.php
php
<?php
return [
App\Providers\AppServiceProvider::class,
// ... other providers ...
Webkul\CustomExpressShipping\Providers\CustomExpressShippingServiceProvider::class,
];- Clear caches:
bash
php artisan optimize:clear- 添加到composer.json(Bagisto根目录下):
json
{
"autoload": {
"psr-4": {
"Webkul\\CustomExpressShipping\\": "packages/Webkul/CustomExpressShipping/src"
}
}
}- 更新自动加载器:
bash
composer dump-autoload- 在中注册服务提供者:
bootstrap/providers.php
php
<?php
return [
App\Providers\AppServiceProvider::class,
// ... 其他服务提供者 ...
Webkul\CustomExpressShipping\Providers\CustomExpressShippingServiceProvider::class,
];- 清除缓存:
bash
php artisan optimize:clearBase Carrier Class Reference
基础承运商类参考
Location:
packages/Webkul/Shipping/src/Carriers/AbstractShipping.phpAll shipping methods extend :
Webkul\Shipping\Carriers\AbstractShippingphp
<?php
namespace Webkul\Shipping\Carriers;
use Webkul\Shipping\Exceptions\CarrierCodeException;
abstract class AbstractShipping
{
/**
* Shipping method carrier code.
*
* @var string
*/
protected $code;
/**
* Shipping method code.
*
* @var string
*/
protected $method;
abstract public function calculate();
/**
* Checks if shipping method is available.
*
* @return array
*/
public function isAvailable()
{
return $this->getConfigData('active');
}
/**
* Returns shipping method carrier code.
*
* @return string
*/
public function getCode()
{
if (empty($this->code)) {
throw new CarrierCodeException('Carrier code should be initialized.');
}
return $this->code;
}
/**
* Return shipping method code.
*
* @return string
*/
public function getMethod()
{
if (empty($this->method)) {
$code = $this->getCode();
return $code . '_' . $code;
}
return $this->method;
}
/**
* Returns shipping method title.
*
* @return array
*/
public function getTitle()
{
return $this->getConfigData('title');
}
/**
* Returns shipping method description.
*
* @return array
*/
public function getDescription()
{
return $this->getConfigData('description');
}
/**
* Retrieve information from shipping configuration.
*
* @param string $field
* @return mixed
*/
public function getConfigData($field)
{
return core()->getConfigData('sales.carriers.' . $this->getCode() . '.' . $field);
}
}位置:
packages/Webkul/Shipping/src/Carriers/AbstractShipping.php所有配送方式都继承自:
Webkul\Shipping\Carriers\AbstractShippingphp
<?php
namespace Webkul\Shipping\Carriers;
use Webkul\Shipping\Exceptions\CarrierCodeException;
abstract class AbstractShipping
{
/**
* Shipping method carrier code.
*
* @var string
*/
protected $code;
/**
* Shipping method code.
*
* @var string
*/
protected $method;
abstract public function calculate();
/**
* Checks if shipping method is available.
*
* @return array
*/
public function isAvailable()
{
return $this->getConfigData('active');
}
/**
* Returns shipping method carrier code.
*
* @return string
*/
public function getCode()
{
if (empty($this->code)) {
throw new CarrierCodeException('Carrier code should be initialized.');
}
return $this->code;
}
/**
* Return shipping method code.
*
* @return string
*/
public function getMethod()
{
if (empty($this->method)) {
$code = $this->getCode();
return $code . '_' . $code;
}
return $this->method;
}
/**
* Returns shipping method title.
*
* @return array
*/
public function getTitle()
{
return $this->getConfigData('title');
}
/**
* Returns shipping method description.
*
* @return array
*/
public function getDescription()
{
return $this->getConfigData('description');
}
/**
* Retrieve information from shipping configuration.
*
* @param string $field
* @return mixed
*/
public function getConfigData($field)
{
return core()->getConfigData('sales.carriers.' . $this->getCode() . '.' . $field);
}
}CartShippingRate Model
CartShippingRate模型
Location:
packages/Webkul/Checkout/src/Models/CartShippingRate.phpphp
<?php
namespace Webkul\Checkout\Models;
use Illuminate\Database\Eloquent\Model;
use Webkul\Checkout\Contracts\CartShippingRate as CartShippingRateContract;
class CartShippingRate extends Model implements CartShippingRateContract
{
protected $fillable = [
'carrier',
'carrier_title',
'method',
'method_title',
'method_description',
'price',
'base_price',
'discount_amount',
'base_discount_amount',
'tax_percent',
'tax_amount',
'base_tax_amount',
'price_incl_tax',
'base_price_incl_tax',
'applied_tax_rate',
];
}位置:
packages/Webkul/Checkout/src/Models/CartShippingRate.phpphp
<?php
namespace Webkul\Checkout\Models;
use Illuminate\Database\Eloquent\Model;
use Webkul\Checkout\Contracts\CartShippingRate as CartShippingRateContract;
class CartShippingRate extends Model implements CartShippingRateContract
{
protected $fillable = [
'carrier',
'carrier_title',
'method',
'method_title',
'method_description',
'price',
'base_price',
'discount_amount',
'base_discount_amount',
'tax_percent',
'tax_amount',
'base_tax_amount',
'price_incl_tax',
'base_price_incl_tax',
'applied_tax_rate',
];
}Key Methods to Implement
需实现的关键方法
| Method | Purpose | Required |
|---|---|---|
| Calculate and return shipping rate | Yes (abstract) |
| Build CartShippingRate object | No (can be inline) |
| Override for custom availability | No (uses default) |
| 方法 | 用途 | 是否必填 |
|---|---|---|
| 计算并返回配送费率 | 是(抽象方法) |
| 构建CartShippingRate对象 | 否(可内联实现) |
| 自定义可用性判断(可重写) | 否(使用默认实现) |
Built-in Shipping Methods
内置配送方式
- FlatRate:
packages/Webkul/Shipping/src/Carriers/FlatRate.php - Free:
packages/Webkul/Shipping/src/Carriers/Free.php
- FlatRate:
packages/Webkul/Shipping/src/Carriers/FlatRate.php - Free:
packages/Webkul/Shipping/src/Carriers/Free.php
Pricing Examples
定价示例
Fixed Rate Shipping
固定费率配送
php
public function calculate()
{
if (! $this->isAvailable()) {
return false;
}
$cartShippingRate = new CartShippingRate;
$cartShippingRate->carrier = $this->getCode();
$cartShippingRate->carrier_title = $this->getConfigData('title');
$cartShippingRate->method = $this->getMethod();
$cartShippingRate->method_title = $this->getConfigData('title');
$cartShippingRate->method_description = $this->getConfigData('description');
$cartShippingRate->price = 15.99;
$cartShippingRate->base_price = 15.99;
return $cartShippingRate;
}php
public function calculate()
{
if (! $this->isAvailable()) {
return false;
}
$cartShippingRate = new CartShippingRate;
$cartShippingRate->carrier = $this->getCode();
$cartShippingRate->carrier_title = $this->getConfigData('title');
$cartShippingRate->method = $this->getMethod();
$cartShippingRate->method_title = $this->getConfigData('title');
$cartShippingRate->method_description = $this->getConfigData('description');
$cartShippingRate->price = 15.99;
$cartShippingRate->base_price = 15.99;
return $cartShippingRate;
}Weight-Based Pricing
按重量定价
php
public function calculate()
{
if (! $this->isAvailable()) {
return false;
}
$cart = Cart::getCart();
$baseRate = 5.00;
$perKg = 2.50;
$price = $baseRate + ($cart->weight * $perKg);
$cartShippingRate = new CartShippingRate;
$cartShippingRate->carrier = $this->getCode();
$cartShippingRate->carrier_title = $this->getConfigData('title');
$cartShippingRate->method = $this->getMethod();
$cartShippingRate->method_title = $this->getConfigData('title');
$cartShippingRate->price = core()->convertPrice($price);
$cartShippingRate->base_price = $price;
return $cartShippingRate;
}php
public function calculate()
{
if (! $this->isAvailable()) {
return false;
}
$cart = Cart::getCart();
$baseRate = 5.00;
$perKg = 2.50;
$price = $baseRate + ($cart->weight * $perKg);
$cartShippingRate = new CartShippingRate;
$cartShippingRate->carrier = $this->getCode();
$cartShippingRate->carrier_title = $this->getConfigData('title');
$cartShippingRate->method = $this->getMethod();
$cartShippingRate->method_title = $this->getConfigData('title');
$cartShippingRate->price = core()->convertPrice($price);
$cartShippingRate->base_price = $price;
return $cartShippingRate;
}Free Shipping Above Threshold
满额免配送费
php
public function calculate()
{
if (! $this->isAvailable()) {
return false;
}
$cart = Cart::getCart();
$threshold = (float) $this->getConfigData('free_shipping_threshold');
$price = $cart->sub_total >= $threshold ? 0 : (float) $this->getConfigData('default_rate');
$cartShippingRate = new CartShippingRate;
$cartShippingRate->carrier = $this->getCode();
$cartShippingRate->carrier_title = $this->getConfigData('title');
$cartShippingRate->method = $this->getMethod();
$cartShippingRate->method_title = $this->getConfigData('title');
$cartShippingRate->price = core()->convertPrice($price);
$cartShippingRate->base_price = $price;
return $cartShippingRate;
}php
public function calculate()
{
if (! $this->isAvailable()) {
return false;
}
$cart = Cart::getCart();
$threshold = (float) $this->getConfigData('free_shipping_threshold');
$price = $cart->sub_total >= $threshold ? 0 : (float) $this->getConfigData('default_rate');
$cartShippingRate = new CartShippingRate;
$cartShippingRate->carrier = $this->getCode();
$cartShippingRate->carrier_title = $this->getConfigData('title');
$cartShippingRate->method = $this->getMethod();
$cartShippingRate->method_title = $this->getConfigData('title');
$cartShippingRate->price = core()->convertPrice($price);
$cartShippingRate->base_price = $price;
return $cartShippingRate;
}Shipping Facade
Shipping Facade
Location:
packages/Webkul/Shipping/src/Shipping.phpThe Shipping facade manages rate collection and processing:
php
class Shipping
{
public function collectRates()
{
// Iterates through all carriers and calls calculate()
// Returns grouped shipping methods with rates
}
public function getGroupedAllShippingRates()
{
// Returns rates grouped by carrier
}
public function getShippingMethods()
{
// Returns available shipping methods
}
}位置:
packages/Webkul/Shipping/src/Shipping.phpShipping Facade负责管理费率的收集和处理:
php
class Shipping
{
public function collectRates()
{
// Iterates through all carriers and calls calculate()
// Returns grouped shipping methods with rates
}
public function getGroupedAllShippingRates()
{
// Returns rates grouped by carrier
}
public function getShippingMethods()
{
// Returns available shipping methods
}
}Package Structure
包结构
packages
└── Webkul
└── CustomExpressShipping
└── src
├── Carriers
│ └── CustomExpressShipping.php # Rate calculation logic
├── Config
│ ├── carriers.php # Shipping method definition
│ └── system.php # Admin configuration
└── Providers
└── CustomExpressShippingServiceProvider.php # Registrationpackages
└── Webkul
└── CustomExpressShipping
└── src
├── Carriers
│ └── CustomExpressShipping.php # 费率计算逻辑
├── Config
│ ├── carriers.php # 配送方式定义
│ └── system.php # 后台管理配置
└── Providers
└── CustomExpressShippingServiceProvider.php # 注册类Testing
测试
Shipping methods can be tested through the checkout flow. Test:
- Method appears in checkout when enabled
- Rate calculation is correct
- Admin configuration saves properly
- Method respects enabled/disabled status
可通过结账流程测试配送方式,需测试:
- 启用后,配送方式是否在结账环节显示
- 费率计算是否正确
- 后台配置是否能正确保存
- 配送方式是否遵循启用/禁用状态
Key Files Reference
关键文件参考
| File | Purpose |
|---|---|
| Base abstract class |
| Flat rate shipping example |
| Free shipping example |
| Default carriers config |
| Shipping facade |
| Shipping rate model |
| Admin config (carrier sections) |
| 文件 | 用途 |
|---|---|
| 基础抽象类 |
| 固定费率配送示例 |
| 免费配送示例 |
| 默认承运商配置 |
| Shipping Facade |
| 配送费率模型 |
| 后台配置(承运商板块) |
Common Pitfalls
常见误区
- Forgetting to merge config in service provider
- Not matching property with config array key
$code - Not registering service provider in
bootstrap/providers.php - Forgetting to run after adding package
composer dump-autoload - Not clearing cache after configuration changes
- Not using for multi-currency support
core()->convertPrice() - Not checking for per-item calculations
isStockable() - Not following PHPDoc conventions with proper punctuation
- 忘记在服务提供者中合并配置
- 属性与配置数组键不匹配
$code - 未在中注册服务提供者
bootstrap/providers.php - 添加包后忘记运行
composer dump-autoload - 修改配置后忘记清除缓存
- 未使用支持多币种
core()->convertPrice() - 按件计算时未检查
isStockable() - 未遵循PHPDoc规范,标点符号使用不当