🚚 فصل ۵: روشهای ارسال پیشرفته
در این فصل یاد میگیرید چطور سیستم ارسال حرفهای، چندمنطقهای و سفارشی برای فروشگاه ایرانی بسازید — از تیپاکس و پست تا محاسبه پویای هزینه بر اساس وزن و موقعیت.
🌍 مفهوم Shipping Zones
ووکامرس از منطقه ارسال (Shipping Zone) استفاده میکند. هر منطقه میتواند چندین روش ارسال داشته باشد:
| منطقه | مناطق پوشش | روشها |
|---|---|---|
| تهران | استان تهران | پیک موتوری، پست پیشتاز |
| شهرستان | سایر استانها | تیپاکس، پست |
| خارج کشور | سایر کشورها | EMS، DHL |
تنظیم از: WooCommerce → Settings → Shipping → Shipping zones
🛠️ ساخت روش ارسال سفارشی
برای ساخت روش ارسال جدید، باید کلاس WC_Shipping_Method را extend کنید:
includes/class-wc-shipping-tipax.php
<?php
defined('ABSPATH') || exit;
class WC_Shipping_Tipax extends WC_Shipping_Method {
public function __construct($instance_id = 0) {
$this->id = 'tipax';
$this->instance_id = absint($instance_id);
$this->method_title = 'تیپاکس';
$this->method_description = 'ارسال با تیپاکس به سراسر کشور';
$this->supports = ['shipping-zones', 'instance-settings', 'instance-settings-modal'];
$this->init();
}
public function init() {
$this->init_form_fields();
$this->init_settings();
$this->title = $this->get_option('title');
$this->cost = $this->get_option('cost');
$this->cost_per_kg = $this->get_option('cost_per_kg');
$this->free_above = $this->get_option('free_above');
add_action('woocommerce_update_options_shipping_' . $this->id,
[$this, 'process_admin_options']);
}
public function init_form_fields() {
$this->instance_form_fields = [
'title' => [
'title' => 'عنوان',
'type' => 'text',
'default' => 'تیپاکس',
],
'cost' => [
'title' => 'هزینه پایه (تومان)',
'type' => 'number',
'default' => '50000',
],
'cost_per_kg' => [
'title' => 'هزینه به ازای هر کیلوگرم',
'type' => 'number',
'default' => '10000',
],
'free_above' => [
'title' => 'ارسال رایگان از مبلغ',
'type' => 'number',
'description' => 'صفر = غیرفعال',
'default' => '0',
],
];
}
public function calculate_shipping($package = []) {
$cost = (float) $this->cost;
$weight = 0;
// محاسبه وزن کل
foreach ($package['contents'] as $item) {
$weight += floatval($item['data']->get_weight()) * $item['quantity'];
}
$cost += $weight * floatval($this->cost_per_kg);
// ارسال رایگان
$cart_total = $package['contents_cost'] ?? 0;
if ($this->free_above > 0 && $cart_total >= $this->free_above) {
$cost = 0;
}
$this->add_rate([
'id' => $this->get_rate_id(),
'label' => $this->title . ($cost == 0 ? ' (رایگان)' : ''),
'cost' => $cost,
'package' => $package,
'meta_data' => [
'وزن کل' => $weight . ' کیلوگرم',
],
]);
}
}
tipax-shipping.php
// ثبت روش ارسال
add_filter('woocommerce_shipping_methods', function($methods) {
$methods['tipax'] = 'WC_Shipping_Tipax';
return $methods;
});
add_action('woocommerce_shipping_init', function() {
require_once __DIR__ . '/includes/class-wc-shipping-tipax.php';
});
⚖️ محاسبه بر اساس وزن و حجم
محاسبه پلکانی (Tier-based)
public function calculate_shipping($package = []) {
$weight = $this->calculate_total_weight($package);
$cost = $this->get_tier_cost($weight);
$this->add_rate([
'id' => $this->get_rate_id(),
'label' => $this->title,
'cost' => $cost,
]);
}
private function get_tier_cost($weight) {
$tiers = [
['max' => 1, 'cost' => 50000], // تا ۱ کیلو
['max' => 5, 'cost' => 80000], // تا ۵ کیلو
['max' => 10, 'cost' => 120000], // تا ۱۰ کیلو
['max' => 30, 'cost' => 200000], // تا ۳۰ کیلو
];
foreach ($tiers as $tier) {
if ($weight <= $tier['max']) return $tier['cost'];
}
// بالای ۳۰ کیلو
return 200000 + (($weight - 30) * 10000);
}
محاسبه با ابعاد (Volumetric)
private function calculate_volumetric_weight($package) {
$total = 0;
foreach ($package['contents'] as $item) {
$product = $item['data'];
$length = $product->get_length() ?: 1;
$width = $product->get_width() ?: 1;
$height = $product->get_height() ?: 1;
// فرمول استاندارد: (طول × عرض × ارتفاع) / 5000 cm³
$volumetric = ($length * $width * $height) / 5000;
$actual = floatval($product->get_weight());
// وزن قابل قبول = max(فیزیکی، حجمی)
$total += max($volumetric, $actual) * $item['quantity'];
}
return $total;
}
🚛 یکپارچهسازی با API تیپاکس
تیپاکس API محاسبه هزینه دارد. برای دریافت قیمت زنده:
public function calculate_shipping($package = []) {
$destination = $package['destination'];
$weight = $this->calculate_total_weight($package);
// فراخوانی API تیپاکس
$response = wp_remote_post('https://api.tipaxco.com/v1/quotation', [
'headers' => [
'Authorization' => 'Bearer ' . $this->api_token,
'Content-Type' => 'application/json',
],
'body' => wp_json_encode([
'origin_city_id' => $this->origin_city_id,
'destination_city_id' => $this->city_to_id($destination['city']),
'weight' => $weight,
'package_count' => count($package['contents']),
]),
'timeout' => 15,
]);
if (is_wp_error($response)) {
// در صورت خطا، fallback به محاسبه دستی
$cost = $this->fallback_calculate($weight);
} else {
$body = json_decode(wp_remote_retrieve_body($response), true);
$cost = $body['data']['price'] ?? $this->fallback_calculate($weight);
}
$this->add_rate([
'id' => $this->get_rate_id(),
'label' => 'تیپاکس - ۲ تا ۳ روز کاری',
'cost' => $cost,
]);
}
// Cache برای جلوگیری از فراخوانی مکرر
private function get_cached_quote($key, $callback) {
$cached = get_transient('tipax_quote_' . $key);
if ($cached !== false) return $cached;
$result = $callback();
set_transient('tipax_quote_' . $key, $result, HOUR_IN_SECONDS);
return $result;
}
💡 بهترین روش: برای جلوگیری از کندی صفحه سبد خرید، نتیجه API را با Transient کش کنید (یک ساعت کافی است).
📮 یکپارچهسازی با پست ایران
پست ایران سرویس پیشتاز و سفارشی دارد:
class WC_Shipping_IranPost extends WC_Shipping_Method {
public function init_form_fields() {
$this->instance_form_fields = [
'service_type' => [
'title' => 'نوع سرویس',
'type' => 'select',
'options' => [
'pishtaz' => 'پیشتاز (۲-۴ روز)',
'sefaresh' => 'سفارشی (۵-۷ روز)',
'EMS' => 'EMS بینالمللی',
],
],
'cod_enabled' => [
'title' => 'پرداخت در محل',
'type' => 'checkbox',
'label' => 'فعالسازی COD',
],
];
}
public function calculate_shipping($package = []) {
$service = $this->get_option('service_type');
$weight = $this->calculate_total_weight($package);
$costs = [
'pishtaz' => 35000 + ($weight * 5000),
'sefaresh' => 25000 + ($weight * 3000),
'EMS' => 150000 + ($weight * 20000),
];
$cost = $costs[$service] ?? 50000;
// اضافه کردن کرایه پرداخت در محل
if ('yes' === $this->get_option('cod_enabled')) {
$cost += 10000;
}
$this->add_rate([
'id' => $this->get_rate_id(),
'label' => 'پست ایران - ' . $this->get_service_label($service),
'cost' => $cost,
]);
}
}
🎯 شرایط ارسال هوشمند
غیرفعال کردن ارسال خاص بر اساس محصول
// مثلاً محصولات بزرگ نمیتوانند با پیک موتوری ارسال شوند
add_filter('woocommerce_package_rates', function($rates, $package) {
$has_large_item = false;
foreach ($package['contents'] as $item) {
if ($item['data']->get_weight() > 30) {
$has_large_item = true;
break;
}
}
if ($has_large_item) {
unset($rates['flat_rate:1']); // حذف پیک موتوری
}
return $rates;
}, 10, 2);
ارسال رایگان شرطی
add_filter('woocommerce_package_rates', function($rates, $package) {
$cart_total = WC()->cart->get_subtotal();
// اگر بالای ۵۰۰ هزار است، فقط ارسال رایگان نمایش بده
if ($cart_total >= 500000 && isset($rates['free_shipping:1'])) {
return ['free_shipping:1' => $rates['free_shipping:1']];
}
return $rates;
}, 10, 2);
ارسال در روزهای خاص
add_filter('woocommerce_package_rates', function($rates, $package) {
$day = date('w'); // 5 = جمعه
// در جمعهها پیک موتوری غیرفعال
if ($day == 5) {
foreach ($rates as $rate_id => $rate) {
if (strpos($rate_id, 'motorcycle') !== false) {
unset($rates[$rate_id]);
}
}
}
return $rates;
}, 10, 2);
📦 ردیابی مرسوله
اضافه کردن قابلیت کد رهگیری به سفارشها:
// متاباکس کد رهگیری در سفارش
add_action('add_meta_boxes', function() {
add_meta_box(
'shipping_tracking',
'کد رهگیری مرسوله',
'render_tracking_metabox',
['shop_order', 'woocommerce_page_wc-orders'], // HPOS support
'side'
);
});
function render_tracking_metabox($post_or_order) {
$order = ($post_or_order instanceof WP_Post)
? wc_get_order($post_or_order->ID)
: $post_or_order;
$tracking = $order->get_meta('_tracking_code');
$carrier = $order->get_meta('_tracking_carrier');
wp_nonce_field('save_tracking', 'tracking_nonce');
?>
get_meta('_tracking_code');
$order->update_meta_data('_tracking_code', $code);
$order->update_meta_data('_tracking_carrier', $carrier);
$order->save();
// اگر کد جدید است، SMS بزن
if ($code && $code !== $old_code) {
send_tracking_sms($order, $code, $carrier);
}
});
function send_tracking_sms($order, $code, $carrier) {
$phone = $order->get_billing_phone();
$name = $order->get_billing_first_name();
$carriers_url = [
'tipax' => 'https://tipaxco.com/track/' . $code,
'post' => 'https://tracking.post.ir/?id=' . $code,
];
$message = sprintf(
"%s عزیز، سفارش %s شما ارسال شد.
کد رهگیری: %s
پیگیری: %s",
$name, $order->get_order_number(), $code,
$carriers_url[$carrier] ?? ''
);
// ارسال با API SMS (مثل کاوهنگار)
wp_remote_post('https://api.kavenegar.com/v1/.../sms/send.json', [
'body' => ['receptor' => $phone, 'message' => $message],
]);
$order->add_order_note('SMS کد رهگیری به مشتری ارسال شد');
}
✅ نمایش به مشتری: کد رهگیری در ایمیل سفارش و صفحه «سفارشهای من» نمایش داده میشود.
📝 خلاصه فصل
- ساختار Shipping Zones را یاد گرفتید
- ساخت روش ارسال سفارشی با Class
- محاسبه پلکانی، وزنی و حجمی
- یکپارچهسازی با API تیپاکس و پست
- شرایط ارسال هوشمند با Filters
- سیستم ردیابی مرسوله با SMS