Webhook GHN: tự cập nhật trạng thái đơn WooCommerce, kèm code PHP

Chào anh em! Shipper Giao Hàng Nhanh (GHN) giao xong từ trưa, khách đã nhận hàng, vậy mà đơn trên website vẫn đứng ở “Đang xử lý”. Nhân viên lại mở khachhang.ghn.vn tra từng mã rồi quay về WooCommerce đổi tay. Việc này giải quyết bằng webhook GHN: GHN tự gọi về website mỗi khi đơn đổi trạng thái, không cần ai ngồi tra.

Webhook GHN đồng bộ trạng thái đơn hàng Giao Hàng Nhanh về website WooCommerce

Làm theo bài, đơn WooCommerce của anh em sẽ tự đổi trạng thái theo GHN, bằng code PHP tự viết hoặc bằng plugin. Thông số webhook trong bài lấy từ tài liệu webhook trạng thái đơn của GHN (đọc tháng 10/2026), còn plugin GHN nhắc tới là sản phẩm mình viết. Code là mẫu tối giản: chạy thử ở môi trường staging và trên bản sao website trước khi dùng thật.

Webhook GHN là gì, gửi khi nào?

Webhook là chiều ngược của API: thay vì website hỏi GHN, GHN gửi một request POST chứa JSON tới đường dẫn bạn đăng ký mỗi khi đơn có thay đổi. Webhook bắt đầu bắn ngay khi đơn có mã vận đơn (order_code).

Để duy trì blog nên mình có làm aff cho 1 số bên hosting. Nhưng dù aff mình cũng chọn 1 số nhà cung cấp uy tín về chất lượng và support nên các bạn cứ yên tâm nhé.

Nếu có mua hosting mà có trong list dưới đây các bạn click vào link trước khi mua để ủng hộ mình nhé. Mình cảm ơn nhiều

Không có webhook thì website phải hẹn giờ gọi API chi tiết đơn cho từng đơn chưa xong: tốn request mà trạng thái vẫn trễ. Có webhook, chuyện đồng bộ trạng thái đơn GHN với WooCommerce chỉ còn là nhận tin và cập nhật đơn. Trường Type cho biết loại sự kiện:

  • create: đơn vừa tạo, luôn gửi riêng.
  • switch_status: đơn đổi trạng thái. Đây là loại dùng để cập nhật đơn trên website.
  • update_weight, update_cod, update_fee, update_payment_type: cập nhật khối lượng, tiền thu hộ, phí, bên trả phí.
  • cod: GHN đã chuyển tiền COD. update_partial_return: cập nhật trả hàng một phần.

Mỗi loại chỉ được gửi nếu GHN đã bật cho tài khoản của bạn.

Khai webhook ở đâu?

Trang khachhang.ghn.vn không có mục cấu hình webhook (mình kiểm trên tài khoản thật ngày 11/10/2026). Theo tài liệu GHN tháng 10/2026, shop tự khai ở Developer Portal:

  1. Vào developer.ghn.vn, đăng nhập bằng tài khoản GHN của shop (Developer Portal có trang đăng nhập riêng, dùng chính tài khoản GHN).
  2. Mở menu tài khoản ở góc trên bên phải, chọn Cấu hình webhook.
  3. Ở tab Order, dán đường dẫn nhận webhook trên website rồi bấm Tạo webhook.

Nếu tài khoản chưa thấy mục Cấu hình webhook thì gửi đường dẫn cho GHN qua CSKH (tổng đài 1900 636677, email cskh@ghn.vn) để được khai giúp. Giao diện Developer Portal có thể đổi, tên mục lệch chút thì cứ tìm đúng tab Order. Các tuỳ chọn tài liệu nhắc tới:

  • Header tùy chỉnh cho phép gửi kèm khoá bí mật để website nhận ra tin thật (phần code bên dưới dùng cách này).
  • Timeout 1–60 giây (mặc định 5 giây) và số lần gửi lại 1–5.
  • Ở mục Quyền · Order, chọn loại sự kiện muốn nhận.
  • Đổi cấu hình cần khoảng 15 phút mới có hiệu lực. Staging (developer.ghn.dev) và Production (developer.ghn.vn) cấu hình riêng, không tự chuyển sang nhau.
  • Webhook cho Ticket (khiếu nại) nằm ở tab Ticket riêng: phải trả HTTP 200, không thì GHN gửi lại 10 lần, cách nhau 5 giây.

Dữ liệu GHN gửi về

Thân request là JSON, khoá viết kiểu PascalCase. Mẫu rút gọn dưới đây theo danh sách trường trong tài liệu, giá trị là minh hoạ:

{
  "ShopID": 123456,
  "Time": "2026-10-11T03:20:15.811Z",
  "OrderCode": "MAVANDONMAU",
  "ClientOrderCode": "WC-1001",
  "Type": "switch_status",
  "Description": "(mô tả sự kiện)",
  "Status": "delivered",
  "Reason": "",
  "ReasonCode": "",
  "CODAmount": 450000,
  "CODTransferDate": null,
  "Weight": 600,
  "ConvertedWeight": 800,
  "Length": 25,
  "Width": 20,
  "Height": 8,
  "PaymentType": 1,
  "IsPartialReturn": false,
  "PartialReturnCode": "",
  "TotalFee": 0,
  "Warehouse": "",
  "ShipperName": "",
  "ShipperPhone": "",
  "PodURL": ""
}
  • Mọi trường luôn có mặt; trường không dùng tới mang giá trị mặc định.
  • OrderCode: mã vận đơn GHN. ClientOrderCode: mã đơn của shop, tức client_order_code gửi lúc tạo đơn. Hai trường này dùng để tìm đơn trên website.
  • Type, Status, Description, Time (ISO 8601): sự kiện gì, trạng thái mới, xảy ra lúc nào.
  • Reason, ReasonCode: chỉ có với các trạng thái ready_to_pick, delivery_fail, return_fail, damage, lost, cancel.
  • Tiền và kiện hàng: CODAmount, CODTransferDate, Fee, TotalFee, PaymentType, Weight, ConvertedWeight, Length/Width/Height. Trong mẫu, kiện 25 × 20 × 8 cm ra ConvertedWeight 800 g, khớp công thức quy đổi dài × rộng × cao ÷ 5.000.
  • ShipperName, ShipperPhone, Warehouse, PodURL. PodURL (ảnh bằng chứng giao hàng) chỉ có khi GHN bật cho tài khoản và khi đơn chuyển delivered; một số trường khác cũng chỉ có khi GHN bật.

Mã trạng thái đơn GHN

Trường Status nhận 23 giá trị theo bảng trạng thái của GHN, mình gom theo chặng:

  • Chặng lấy hàng gồm ready_to_pick, picking, money_collect_picking, picked.
  • Ở kho và trung chuyển có storing, sorting, transporting.
  • Chặng giao hàng gồm delivering, money_collect_delivering, delivered, delivery_fail.
  • Chặng hoàn hàng gồm waiting_to_return, return, return_transporting, return_sorting, returning, return_fail, returned.
  • Nhóm huỷ và sự cố gồm cancel, exception, lost, damage, scrap.

Trạng thái kết thúc gồm delivered, returned, cancel, exception, lost, damage, scrap. Mình chỉ đổi trạng thái đơn trên website ở nhóm này; mốc giữa đường thì lưu lại để xem, đổi trạng thái theo từng mốc làm đơn nhảy liên tục và dễ bắn email nhầm cho khách.

ReasonCode chia theo nhóm: huỷ bởi người gửi (GHN-CO…), lấy hàng thất bại (GHN-PFA…, GHN-PFC…), huỷ tại điểm lấy (GHN-PCB…), giao thất bại (GHN-DFC…), người nhận từ chối (GHN-DCD…), trả hàng thất bại (GHN-RFE…), giao lại (GHN-RDAI01, GHN-RDC001, lúc này Reason rỗng). GHN có thể bổ sung mã mới, nên code phải chấp nhận mã lạ thay vì báo lỗi. Trên giao diện shop, GHN gom các trạng thái thành 8 nhóm dễ đọc hơn: đơn nháp; chờ bàn giao; đã bàn giao, đang giao; đã bàn giao, đang hoàn hàng; chờ xác nhận giao lại; hoàn tất; đơn huỷ; hàng thất lạc, hư hỏng.

Trả lời GHN thế nào cho đúng?

  • ✅ Trả HTTP 2xx là GHN tính thành công.
  • 🚨 4xx (trừ 408, 429) bị coi là thất bại vĩnh viễn, không gửi lại. Tường lửa chặn và trả 403 là mất tin luôn.
  • Gặp 5xx, 408, 429 hoặc quá thời gian chờ thì GHN gửi lại theo lịch giãn dần (30 giây, 2 phút, 5 phút, 10 phút…); tổng số lần gửi bằng 1 cộng số lần gửi lại bạn cấu hình.
  • Tin của từng đơn đi theo thứ tự trước sau. Một callback lỗi liên tục sẽ giữ các callback sau của cùng đơn đó lại; đơn khác không ảnh hưởng. Endpoint hồi phục thì phần tồn được đẩy tiếp đúng thứ tự.
  • Cùng một sự kiện có thể tới nhiều lần, nên endpoint phải xử lý lặp lại vô hại: khử trùng theo OrderCode + Type + Time.

Suy ra cách viết endpoint: kiểm khoá, ghi nhận, trả 200 ngay. Tin không khớp đơn nào cũng trả 200, đừng trả 404 hay 500: 404 làm GHN bỏ tin, 500 làm GHN gửi lại nhiều lần và giữ các tin sau của đơn đó. Chỉ trả 5xx khi website lỗi tạm thời thật sự và bạn muốn GHN gửi lại. Thời gian chờ mặc định chỉ 5 giây, việc nặng nên đẩy sang chạy nền.

Bảo vệ endpoint nhận webhook

  • Tài liệu GHN không nêu chữ ký (HMAC) cho payload; cách xác thực tài liệu gợi ý là Header tùy chỉnh. Đặt một khoá dài, ngẫu nhiên, gửi qua header đó và so bằng hash_equals.
  • Nhờ CSKH khai giúp mà không đặt được header thì để khoá ngay trên đường dẫn (ví dụ ?key=…), giống cách plugin của mình làm.
  • Chỉ khai đường dẫn https://, để khoá không đi dạng chữ trơn.
  • Tìm đơn bằng mã vận đơn rồi đối chiếu lại, khử trùng trước khi đổi gì.
  • Với thay đổi quan trọng như giao thành công hay huỷ, muốn chắc hơn nữa thì gọi API v2/shipping-order/detail kiểm lại trước khi đổi trạng thái đơn. Đánh đổi là thêm một lời gọi API mỗi tin.

Code PHP nhận webhook trong WordPress

Đoạn code dưới tạo một REST route, kiểm khoá, khử trùng theo OrderCode + Type + Time, lưu trạng thái, đổi trạng thái đơn khi đơn kết thúc rồi trả 200. Mã vận đơn đọc ở meta _devvn_ghn_order_code, mã đơn shop có dạng WC-{ID}, đúng như đoạn tạo đơn lưu lại. Hàm gọi API và tạo đơn có ở bài tích hợp API GHN.

Khoá bí mật để trong wp-config.php, giống hệt chuỗi khai ở Header tùy chỉnh:

define( 'DEVVN_GHN_WEBHOOK_KEY', 'chuoi-bi-mat-tu-dat' );
/**
 * Đăng ký endpoint POST /wp-json/devvn-ghn/v1/webhook nhận callback trạng thái đơn GHN.
 *
 * @return void
 */
function devvn_ghn_register_webhook() {
	register_rest_route(
		'devvn-ghn/v1',
		'/webhook',
		array(
			'methods'             => 'POST',
			'callback'            => 'devvn_ghn_webhook',
			'permission_callback' => '__return_true',
		)
	);
}
add_action( 'rest_api_init', 'devvn_ghn_register_webhook' );

/**
 * Kiểm khoá bí mật: header X-Devvn-Key (khai ở Header tùy chỉnh) hoặc tham số key trên URL.
 *
 * @param WP_REST_Request $request Request GHN gửi tới.
 * @return bool
 */
function devvn_ghn_webhook_authorized( WP_REST_Request $request ) {
	$key = (string) $request->get_header( 'x-devvn-key' );
	if ( '' === $key ) {
		$query = $request->get_query_params();
		$key   = isset( $query['key'] ) ? (string) $query['key'] : '';
	}
	return '' !== $key && hash_equals( DEVVN_GHN_WEBHOOK_KEY, $key );
}

/**
 * Tìm đơn WooCommerce theo mã vận đơn GHN, ưu tiên ClientOrderCode dạng WC-{ID}.
 *
 * @param string $order_code        Mã vận đơn (OrderCode).
 * @param string $client_order_code Mã đơn của shop (ClientOrderCode).
 * @return WC_Order|null
 */
function devvn_ghn_find_order( $order_code, $client_order_code ) {
	$order = null;
	if ( 0 === strpos( $client_order_code, 'WC-' ) ) {
		$order = wc_get_order( absint( substr( $client_order_code, 3 ) ) );
	}
	if ( ! $order ) {
		$found = wc_get_orders(
			array(
				'limit'      => 1,
				'meta_key'   => '_devvn_ghn_order_code',
				'meta_value' => $order_code,
			)
		);
		$order = $found ? $found[0] : null;
	}
	return ( $order && $order->get_meta( '_devvn_ghn_order_code' ) === $order_code ) ? $order : null;
}

/**
 * Nhận callback GHN: kiểm khoá, khử trùng, lưu trạng thái, đổi trạng thái đơn khi kết thúc, trả 200 ngay.
 *
 * @param WP_REST_Request $request Request GHN gửi tới.
 * @return WP_REST_Response
 */
function devvn_ghn_webhook( WP_REST_Request $request ) {
	if ( ! devvn_ghn_webhook_authorized( $request ) ) {
		return new WP_REST_Response( array( 'message' => 'Sai khoá' ), 401 );
	}
	$ok    = new WP_REST_Response( array( 'message' => 'OK' ), 200 );
	$body  = (array) $request->get_json_params();
	$body += array(
		'OrderCode'       => '',
		'ClientOrderCode' => '',
		'Type'            => '',
		'Status'          => '',
		'Time'            => '',
		'Reason'          => '',
	);
	$code = sanitize_text_field( (string) $body['OrderCode'] );
	$type = sanitize_key( (string) $body['Type'] );
	if ( '' === $code || 'switch_status' !== $type ) {
		return $ok;
	}
	$order = devvn_ghn_find_order( $code, sanitize_text_field( (string) $body['ClientOrderCode'] ) );
	if ( ! $order ) {
		return $ok;
	}

	$event  = md5( $code . '|' . $type . '|' . (string) $body['Time'] );
	$events = $order->get_meta( '_devvn_ghn_events' );
	$events = is_array( $events ) ? $events : array();
	if ( in_array( $event, $events, true ) ) {
		return $ok;
	}
	$events[] = $event;
	$status   = sanitize_key( (string) $body['Status'] );
	$order->update_meta_data( '_devvn_ghn_events', array_slice( $events, -50 ) );
	$order->update_meta_data( '_devvn_ghn_status', $status );

	$note = 'GHN: ' . $status;
	if ( '' !== (string) $body['Reason'] ) {
		$note .= ' (' . sanitize_text_field( (string) $body['Reason'] ) . ')';
	}
	$map = array(
		'delivered' => 'completed',
		'cancel'    => 'cancelled',
		'returned'  => 'failed',
	);
	if ( isset( $map[ $status ] ) ) {
		$order->set_status( $map[ $status ], $note );
	} else {
		$order->add_order_note( $note );
	}
	$order->save();
	return $ok;
}
  • URL khai với GHN là https://ten-mien-cua-ban/wp-json/devvn-ghn/v1/webhook, kèm Header tùy chỉnh X-Devvn-Key mang khoá bí mật; nhờ CSKH khai giúp thì dùng https://ten-mien-cua-ban/wp-json/devvn-ghn/v1/webhook?key=chuoi-bi-mat-tu-dat, còn website để đường dẫn tĩnh kiểu mặc định (Plain) thì thay phần /wp-json/… bằng /?rest_route=/devvn-ghn/v1/webhook.
  • Sai khoá thì code trả 401 để lỗi cấu hình lộ ra sớm (GHN coi là thất bại, không gửi lại), còn tin hợp lệ nào cũng trả 200, kể cả tin trùng, tin không khớp đơn hay loại sự kiện không xử lý.
  • Code chỉ xử lý switch_status; muốn ghi nhận ngày GHN chuyển tiền COD thì bắt thêm Type là cod theo cùng kiểu.
  • Code đổi delivered thành Đã hoàn thành, cancel thành Đã huỷ, returned thành Thất bại (để tách đơn hoàn về khỏi đơn huỷ trước khi gửi); trạng thái khác chỉ lưu meta và thêm ghi chú đơn, shop có trạng thái riêng thì sửa trong $map.
  • Code tìm đơn theo ClientOrderCode trước (không phải truy vấn meta), không có mới tìm theo meta; đường nào cũng đối chiếu lại mã vận đơn vì trên kho đơn cũ (chưa bật HPOS) wc_get_orders() có thể bỏ qua điều kiện meta và trả về một đơn khác.
  • Để khử trùng, code giữ 50 khoá sự kiện gần đây trong meta của đơn; tin trùng trả 200 và không làm gì thêm.

Đổi đơn sang Đã hoàn thành kéo theo email WooCommerce gửi khách ngay trong request, dễ làm phản hồi vượt 5 giây. Cho email gửi nền bằng một dòng (việc nặng hơn thì đẩy sang Action Scheduler đi kèm WooCommerce):

add_filter( 'woocommerce_defer_transactional_emails', '__return_true' );

Bắn thử một bản tin

Chỉ làm trên bản sao website hoặc đơn thử có meta _devvn_ghn_order_code đúng mã dưới. Trạng thái picked không có trong $map nên chỉ thêm ghi chú:

curl -i -X POST 'https://ten-mien-cua-ban/wp-json/devvn-ghn/v1/webhook' \
  -H 'Content-Type: application/json' \
  -H 'X-Devvn-Key: chuoi-bi-mat-tu-dat' \
  -d '{"OrderCode":"MA_VAN_DON_THU","ClientOrderCode":"WC-123","Type":"switch_status","Status":"picked","Time":"2026-10-11T03:20:15.811Z","Reason":""}'

Đúng khoá thì dòng đầu là HTTP/1.1 200 OK (hoặc HTTP/2 200), sai khoá ra 401. Ra 403, 503 thường là tường lửa chặn; ra 301 là đường dẫn đang bị chuyển hướng, phải khai lại đúng đường dẫn cuối.

Dùng plugin: phần nhận webhook có sẵn

Cách lấy đường dẫn trong plugin và khai với GHN có trong video dưới, bắt đầu ở giây 0:09.

Web dùng plugin GHN cho WooCommerce của mình thì phần nhận webhook có sẵn, bạn chỉ cần đưa đường dẫn cho GHN:

  1. Vào WooCommerce → Cài đặt GHN, tab Cập nhật trạng thái tự động.
  2. Ô Webhook URL có sẵn đường dẫn dạng https://ten-mien-cua-ban/wp-admin/admin-ajax.php?action=devvn_ghn_webhook&hash=…, trong đó hash là chuỗi 24 ký tự sinh ngẫu nhiên. Bấm Lưu thay đổi trước: hash chỉ có hiệu lực sau khi lưu.
  3. Chép đường dẫn, dán vào mục Cấu hình webhook trên Developer Portal của GHN (theo tài liệu GHN tháng 10/2026). Tài khoản chưa thấy mục này thì gửi đường dẫn cho GHN qua CSKH để được khai giúp; trang cài đặt plugin cũng ghi “Hãy gửi url bên dưới cho GHN để họ cấu hình Webhook nhé”.
  4. Đợi khoảng 15 phút cho cấu hình có hiệu lực, rồi theo dõi một đơn thật.
Tab Cập nhật trạng thái tự động trong plugin GHN với ô Webhook URL, link Làm mới Webhook URL và nút Lưu thay đổi
Tab Cập nhật trạng thái tự động: chép Webhook URL gửi cho GHN. Dữ liệu trong ảnh là mẫu.

⚠️ Link Làm mới Webhook URL sinh hash mới. Làm mới rồi lưu thì đường dẫn cũ hết hiệu lực, phải cập nhật lại bên GHN. Khoá bí mật của plugin chính là tham số hash trên đường dẫn: plugin so nó với hash đã lưu trước khi nhận tin.

Plugin ánh xạ trạng thái theo cách cố định, không có bảng để chỉnh:

  • cancel: đơn chuyển Đã huỷ và plugin gỡ mã vận đơn khỏi đơn, để bạn tạo vận đơn mới được.
  • delivered: đơn chuyển Hoàn thành.
  • Các trạng thái khác (đang lấy, đang giao, hoàn hàng…) không đổi trạng thái đơn WooCommerce, chỉ cập nhật dòng “Trạng thái” trong hộp Giao Hàng NHANH (GHN) của đơn, hiện bằng nhãn tiếng Việt.
  • Plugin không tự ghi ghi chú vào đơn. Ghi chú chỉ xuất hiện khi trạng thái đơn đổi, do chính WooCommerce ghi.
Hộp Giao Hàng NHANH (GHN) trong trang sửa đơn WooCommerce với mã vận đơn, nút Hủy đơn hàng, In vận đơn theo mẫu GHN và dòng Trạng thái
Dòng Trạng thái trong hộp GHN của đơn được webhook cập nhật. Mã vận đơn trong ảnh là mã mẫu.

Lịch sử vận chuyển chi tiết thì plugin không lưu từ webhook: mỗi lần khách mở Tài khoản → Xem đơn hàng hay trang tra cứu, plugin gọi thẳng API chi tiết đơn của GHN. Nhờ vậy khách vẫn xem được các mốc vận chuyển kể cả khi webhook chưa khai. Chi tiết có ở trang webhook trong tài liệu plugin. Tạo vận đơn từ WooCommerce để webhook có mã mà bám vào, mình viết ở bài cách tạo đơn GHN.

Webhook không chạy: kiểm theo thứ tự này

  1. Site chạy ở máy local, đang bảo trì hay khoá mật khẩu thì GHN không gửi vào được, nên trước hết website phải gọi được từ Internet.
  2. Khai http:// trong khi site chuyển sang https://, lệch có/không www hay thiếu một ký tự dễ khiến request dừng ở 301, 404, mà GHN chỉ tính thành công khi nhận mã 2xx; chứng chỉ SSL hết hạn cũng làm request hỏng.
  3. Cloudflare (chế độ chống bot), tường lửa máy chủ hay plugin bảo mật có thể chặn POST từ máy chủ lạ vào admin-ajax.php hay /wp-json/; bị trả 403 là GHN bỏ tin luôn, nên tạo quy tắc cho phép đúng đường dẫn webhook.
  4. Với plugin, hash chỉ có hiệu lực sau khi bấm Lưu; vừa làm mới URL thì phải khai lại bên GHN.
  5. Mới khai chưa đủ 15 phút thì đợi thêm, còn khai trên staging trong khi đơn tạo ở production (hoặc ngược lại) thì không chạy vì hai môi trường cấu hình riêng.
  6. Website phải trả 2xx trong thời gian chờ, mặc định chỉ 5 giây; lỗi PHP, máy chủ quá tải hay plugin khác chạy nặng khi đơn đổi trạng thái đều làm hỏng phản hồi.
  7. Đơn tạo tay trên khachhang.ghn.vn mà không lưu mã vận đơn vào WooCommerce thì webhook không có đơn nào để cập nhật.
  8. Plugin chỉ đổi trạng thái đơn khi huỷ hoặc giao thành công, mốc khác chỉ đổi dòng Trạng thái trong hộp GHN theo đúng thiết kế.

Không muốn tự viết và bảo trì endpoint thì plugin có sẵn đường dẫn webhook kèm khoá, tự xử lý huỷ và giao thành công, có cả trang để khách tra cứu đơn:

Câu hỏi thường gặp

Có phải nhờ GHN bật webhook không?

Theo tài liệu GHN tháng 10/2026, shop tự khai ở mục Cấu hình webhook trên Developer Portal. Tài khoản chưa thấy mục này thì gửi đường dẫn cho GHN qua CSKH để được khai giúp.

GHN có ký payload webhook không?

Tài liệu không nêu chữ ký nào. Xác thực bằng khoá bí mật tự đặt, gửi qua Header tùy chỉnh hoặc gắn trên đường dẫn.

Website lỗi một lúc thì có mất trạng thái không?

Lỗi 5xx hay quá thời gian chờ thì GHN gửi lại theo lịch giãn dần, các tin sau của cùng đơn được giữ lại và đẩy tiếp đúng thứ tự khi website hồi phục. Hết số lần gửi lại đã cấu hình thì tin bị bỏ. Lỗi 4xx (trừ 408, 429) thì GHN không gửi lại.

Plugin có ghi chú vào đơn mỗi lần GHN đổi trạng thái không?

Không. Plugin chỉ đổi đơn sang Đã huỷ hoặc Hoàn thành ở hai trạng thái cancel và delivered; các mốc khác cập nhật dòng Trạng thái trong hộp GHN của đơn.

Vướng chỗ nào cứ để lại bình luận, nhớ che khoá bí mật, hash webhook và số điện thoại khách trước khi dán log nhé. 🚀

Bài viết trong series

Kết nối WooCommerce với Giao Hàng Nhanh

0/9đã đọc
  1. 1 Đăng ký tài khoản GHN cho shop: từng bước trên web và app Đang đọc Đã đọc
  2. 2 Lấy API token GHN và ShopId: từng bước, IP tin cậy và lỗi 401 Đang đọc Đã đọc
  3. 3 Kết nối GHN với website: nền tảng, API hay plugin WooCommerce Đang đọc Đã đọc
  4. 4 Cách tạo đơn GHN trên máy tính, điện thoại, Excel và từ website Đang đọc Đã đọc
  5. 5 Cách tính phí ship GHN: khối lượng quy đổi, bảng giá, phụ phí Đang đọc Đã đọc
  6. 6 Phí COD GHN: phí thu hộ, lịch chuyển tiền và đối soát Đang đọc Đã đọc
  7. 7 In vận đơn GHN: chọn khổ A5, 80 x 80, 52 x 70 và cách in từng bước Đang đọc Đã đọc
  8. 8 Webhook GHN: tự cập nhật trạng thái đơn WooCommerce, kèm code PHP Đang đọc Đã đọc
  9. 9 Tích hợp API GHN bằng PHP cho WordPress: tính phí, tạo đơn, in, huỷ Đang đọc Đã đọc
Sản phẩm nổi bật của Toản
x