Kalau kau guna plugin J&T Express untuk kedai WooCommerce kau, kau mungkin perasan satu kelakuan yang mengelirukan: customer terima email “Order Processing” walaupun payment dah failed atau dah canceled di gateway.
Setakat 13 Februari 2026, isu ni masih ada dalam versi trunk semasa plugin tu. Ini pecahan kenapa ia berlaku dan macam mana kau boleh betulkan.
Masalahnya: trigger email global
Isu ni duduk dalam fungsi order_status_changed_notification yang ada dalam jt-express/admin/class-jnt-status.php.
Plugin ni hook ke woocommerce_order_status_changed. Tapi kod disusun sampai method trigger() untuk email “Processing Order” dipanggil setiap kali apa-apa status berubah, tak kira status baru tu sama dengan status logistik custom J&T ke tak.
Kod yang terdedah
Dalam fail asal (sekitar baris 88), logiknya macam ni:
public function order_status_changed_notification($order_id, $status_from, $status_to)
{
$mailer = WC()->mailer()->get_emails();
// If/Else checks for J&T statuses...
// BUG: These lines run on EVERY status change (e.g., Pending -> Failed)
$mailer['WC_Email_Customer_Processing_Order']->settings['subject'] = $subject;
$mailer['WC_Email_Customer_Processing_Order']->settings['heading'] = $heading;
$mailer['WC_Email_Customer_Processing_Order']->trigger($order_id);
}
Sebab panggilan trigger() tu tak dibungkus dalam semakan bersyarat, WooCommerce hantar email “Processing” walaupun order tu baru je bergerak dari Pending Payment ke Failed.
Penyelesaian: logik bersyarat
Untuk betulkan ni, kita kena pastikan email hanya trigger kalau $status_to sama dengan salah satu status logistik J&T yang spesifik (jnt-pending, jnt-pickup, atau jnt-out-delivery).
Fix yang dah dioptimum
Ganti fungsi dalam class-jnt-status.php dengan kod berikut:
public function order_status_changed_notification($order_id, $status_from, $status_to)
{
$mailer = WC()->mailer()->get_emails();
// 1. Define our target statuses
$target_statuses = ['jnt-pending', 'jnt-pickup', 'jnt-out-delivery'];
// 2. Only proceed if the new status is one of ours
if (in_array($status_to, $target_statuses)) {
// Map statuses to their respective subjects/headings
if ($status_to == 'jnt-pending') {
$subject = $heading = 'Your Order is Pending to Pickup';
} elseif ($status_to == 'jnt-pickup') {
$subject = $heading = 'Your Order has been Picked up';
} elseif ($status_to == 'jnt-out-delivery') {
$subject = $heading = 'Your Order is out for Delivery';
}
// 3. Trigger the email ONLY for the statuses defined above
$email = $mailer['WC_Email_Customer_Processing_Order'];
$email->settings['subject'] = $subject;
$email->settings['heading'] = $heading;
$email->trigger($order_id);
}
}
Kenapa ia berkesan
Dengan bungkus logik dalam in_array($status_to, $target_statuses), kita cipta satu “gatekeeper.” Kalau customer cancel payment dan status bergerak ke failed, kod nampak yang failed bukan dalam senarai $target_statuses kita, dan buat apa-apa pun tak. Tak ada lagi email terhantar secara tak sengaja!
Nota untuk developer: Sebab ni perubahan pada fail core plugin, ingat yang update plugin di masa depan mungkin timpa perubahan ni. Elok simpan snippet fix ni, atau hubungi developer J&T supaya diorang masukkan validation ni dalam release akan datang.
Rasa berguna? Kongsi dengan web builder lain yang guna J&T Express, supaya diorang terselamat dari sakit kepala dengan customer support!

Leave a Reply
You must be logged in to post a comment.