← บทความทั้งหมด

WooCommerce ส่งฟรีหายตอนใช้คูปอง — บั๊กลำดับการคำนวณที่เจอบ่อย

· อ่าน 7 นาที

มีร้าน WooCommerce ร้านหนึ่งที่ผมดูแล ตั้งเกณฑ์ “ส่งฟรีเมื่อยอดถึง 900 บาท” และรับคูปองส่วนลดด้วย อยู่มาวันหนึ่งลูกค้าทักมาว่า ยอดสินค้าเกิน 900 อยู่แล้ว แต่พอใส่คูปองกลับโดนคิดค่าส่ง ทั้งที่ควรได้ส่งฟรี

ฟังดูเหมือน bug ของธีมหรือปลั๊กอินคูปอง แต่จริง ๆ มันคือพฤติกรรม default ของ WooCommerce core เอง บทความนี้เล่าว่ามันเกิดอะไรขึ้น ทำไม และแก้ยังไงให้จบ

อาการ

สมมติเกณฑ์ส่งฟรี = 900 บาท ลูกค้าใช้คูปองลด 150 บาท:

ขั้นตอนค่า
ยอดสินค้า1,020
หักคูปอง−150
ยอดหลังคูปอง870 → ต่ำกว่า 900
ระบบบวกค่าส่ง+100
สุทธิที่ลูกค้าจ่าย (ผิด)970

ลูกค้ามองว่า “ฉันซื้อตั้ง 1,020 ทำไมไม่ได้ส่งฟรี” — ซึ่งถูกของเขา เพราะยอดสินค้าจริงเกินเกณฑ์ไปแล้ว ส่วนลดคูปองไม่ควรมาทำให้เสียสิทธิ์ส่งฟรี

ต้นเหตุ

WooCommerce เทียบเกณฑ์ส่งฟรีกับ “ยอดหลังหักส่วนลด” ไม่ใช่ “ยอดสินค้าก่อนคูปอง”

ถ้าไปดูใน core ที่คลาส WC_Shipping_Free_Shipping::is_available() มันคำนวณยอดมาเทียบเกณฑ์ประมาณนี้:

$total = WC()->cart->get_displayed_subtotal();

if ( 'no' === $this->ignore_discounts ) {
    // หักส่วนลดออกจากยอดก่อนเอาไปเทียบเกณฑ์
    $total = $total - WC()->cart->get_discount_total();
}

$has_met_min_amount = $total >= $this->min_amount;

ประเด็นอยู่ที่ $this->ignore_discountsค่า default คือ 'no' แปลว่า WooCommerce จะ หักคูปองออกก่อน แล้วค่อยเอายอดที่เหลือไปเทียบกับเกณฑ์ส่งฟรี นี่คือต้นเหตุทั้งหมด ไม่ใช่บั๊กของธีมหรือปลั๊กอินอื่นเลย

วิธีแก้

ในการตั้งค่า Free Shipping method ของ WooCommerce มี checkbox อยู่ตัวหนึ่ง:

“Apply minimum order rule before coupon discount”

ติ๊กอันนี้ (ค่านี้แมปกับ ignore_discounts = yes ภายใน) WooCommerce จะเอา ยอดสินค้าก่อนหักคูปอง ไปเทียบเกณฑ์ส่งฟรีแทน

ตั้งที่: WooCommerce → Settings → Shipping → เลือก Zone → แก้ Free Shipping method

ผลหลังแก้ จากเคสเดิม:

1,020 ≥ 900  →  เข้าเกณฑ์ส่งฟรี
สุทธิ = 1,020 − 150 = 870 บาท  (ไม่มีค่าส่ง) ✅

ถ้าธีมเขียน logic ค่าส่งเอง

บางธีม/ปลั๊กอินไม่ได้ใช้ free shipping มาตรฐานของ Woo แต่เขียนเงื่อนไขเอง กรณีนั้น setting ด้านบนจะไม่มีผล ต้องไปแก้ที่จุดเทียบยอด หรือ hook ตัวนี้:

add_filter( 'woocommerce_shipping_free_shipping_is_available', function ( $is_available, $package, $method ) {
    // ใช้ยอดก่อนหักคูปองมาเทียบเกณฑ์เอง
    $subtotal = WC()->cart->get_displayed_subtotal();
    return $subtotal >= 900;
}, 10, 3 );

⚠️ ถ้าแก้ในไฟล์ธีมโดยตรง พอ Woo หรือธีมอัปเดตทับ fix จะหาย — ใส่ใน child theme หรือปลั๊กอินเล็ก ๆ ของตัวเองเสมอ

เช็กลิสต์ก่อนปิดงาน

บั๊กนี้เจอได้กับ ทุกร้าน WooCommerce ที่มีส่งฟรี + คูปองพร้อมกัน ก่อนส่งงานลองเทสเคสขอบพวกนี้:

  • เช็กค่า ignore_discounts / checkbox “before coupon discount” เป็นอย่างแรก
  • ยอดพอดีเกณฑ์เป๊ะ ๆ (เช่น 900 พอดี)
  • คูปองแบบ % เทียบกับคูปองจำนวนเงินคงที่
  • คูปองชนิด “ส่งฟรี” โดยเฉพาะ
  • ยอดตอนสร้างออเดอร์ฝั่ง backend ใช้ลำดับเดียวกับหน้า checkout

จุดที่คนมองข้ามคือข้อสุดท้าย — หน้า cart/checkout แสดงถูก แต่ตอนระบบสร้างออเดอร์จริงคำนวณคนละแบบ ทำให้ยอดในระบบหลังบ้านเพี้ยน ต้องยืนยันว่าทั้งสองฝั่งใช้ตรรกะเดียวกัน


บทเรียนนี้กลั่นจากงานจริง — ถ้าเจอเคสคล้าย ๆ กันหรืออยากเสริม ทักมาคุยกันได้ที่ ช่องทางติดต่อ