-
- First Name *
- setBillingData({ ...billingData, firstName: e.target.value })}
- className="w-full border rounded-lg px-4 py-2"
- />
-
-
- Last Name *
- setBillingData({ ...billingData, lastName: e.target.value })}
- className="w-full border rounded-lg px-4 py-2"
- />
-
-
- Email Address *
- setBillingData({ ...billingData, email: e.target.value })}
- className="w-full border rounded-lg px-4 py-2"
- />
-
-
- Phone *
- setBillingData({ ...billingData, phone: e.target.value })}
- className="w-full border rounded-lg px-4 py-2"
- />
-
+ {/* All fields conditionally rendered based on API response */}
+ {/* This allows ANY field to be hidden via PHP snippet */}
+ {getBillingField('billing_first_name') && (
+
+ {getBillingField('billing_first_name')?.label || 'First Name'} {getBillingField('billing_first_name')?.required && '*'}
+ setBillingData({ ...billingData, firstName: e.target.value })}
+ className="w-full border rounded-lg px-4 py-2"
+ />
+
+ )}
+ {getBillingField('billing_last_name') && (
+
+ {getBillingField('billing_last_name')?.label || 'Last Name'} {getBillingField('billing_last_name')?.required && '*'}
+ setBillingData({ ...billingData, lastName: e.target.value })}
+ className="w-full border rounded-lg px-4 py-2"
+ />
+
+ )}
+ {getBillingField('billing_email') && (
+
+ {getBillingField('billing_email')?.label || 'Email Address'} {getBillingField('billing_email')?.required && '*'}
+ setBillingData({ ...billingData, email: e.target.value })}
+ className="w-full border rounded-lg px-4 py-2"
+ />
+
+ )}
+ {getBillingField('billing_phone') && (
+
+ {getBillingField('billing_phone')?.label || 'Phone'} {getBillingField('billing_phone')?.required && '*'}
+ setBillingData({ ...billingData, phone: e.target.value })}
+ className="w-full border rounded-lg px-4 py-2"
+ />
+
+ )}
{/* Address fields - only for physical products */}
{!isVirtualOnly && (
<>
-
- Street Address *
- setBillingData({ ...billingData, address: e.target.value })}
- className="w-full border rounded-lg px-4 py-2"
- />
-
- {/* City field - hidden if PHP sets type to 'hidden' */}
- {!isFieldHidden('billing_city') && (
-
-
City *
+ {getBillingField('billing_address_1') && (
+
+ {getBillingField('billing_address_1')?.label || 'Street Address'} {getBillingField('billing_address_1')?.required && '*'}
setBillingData({ ...billingData, address: e.target.value })}
+ className="w-full border rounded-lg px-4 py-2"
+ />
+
+ )}
+ {/* City field - conditionally rendered based on API */}
+ {getBillingField('billing_city') && (
+
+ {getBillingField('billing_city')?.label || 'City'} {getBillingField('billing_city')?.required && '*'}
+ setBillingData({ ...billingData, city: e.target.value })}
className="w-full border rounded-lg px-4 py-2"
/>
)}
- {/* Country field - hidden if PHP sets type to 'hidden' */}
- {!isFieldHidden('billing_country') && (
+ {/* Country field - conditionally rendered based on API */}
+ {getBillingField('billing_country') && (
- Country *
+ {getBillingField('billing_country')?.label || 'Country'} {getBillingField('billing_country')?.required && '*'}
)}
- {/* State field - hidden if PHP sets type to 'hidden' */}
- {!isFieldHidden('billing_state') && (
+ {/* State field - conditionally rendered based on API */}
+ {getBillingField('billing_state') && (
-
State / Province *
+
{getBillingField('billing_state')?.label || 'State / Province'} {getBillingField('billing_state')?.required && '*'}
{billingStateOptions.length > 0 ? (
)}
- {/* Postcode field - hidden if PHP sets type to 'hidden' */}
- {!isFieldHidden('billing_postcode') && (
+ {/* Postcode field - conditionally rendered based on API */}
+ {getBillingField('billing_postcode') && (
- Postcode / ZIP *
+ {getBillingField('billing_postcode')?.label || 'Postcode / ZIP'} {getBillingField('billing_postcode')?.required && '*'}
setBillingData({ ...billingData, postcode: e.target.value })}
className="w-full border rounded-lg px-4 py-2"
@@ -919,23 +945,23 @@ export default function Checkout() {
className="w-full border rounded-lg px-4 py-2"
/>
- {/* City field - hidden if PHP sets type to 'hidden' */}
- {!isFieldHidden('shipping_city') && (
+ {/* City field - conditionally rendered based on API */}
+ {getShippingField('shipping_city') && (
- City *
+ {getShippingField('shipping_city')?.label || 'City'} {getShippingField('shipping_city')?.required && '*'}
setShippingData({ ...shippingData, city: e.target.value })}
className="w-full border rounded-lg px-4 py-2"
/>
)}
- {/* Country field - hidden if PHP sets type to 'hidden' */}
- {!isFieldHidden('shipping_country') && (
+ {/* Country field - conditionally rendered based on API */}
+ {getShippingField('shipping_country') && (
- Country *
+ {getShippingField('shipping_country')?.label || 'Country'} {getShippingField('shipping_country')?.required && '*'}
)}
- {/* State field - hidden if PHP sets type to 'hidden' */}
- {!isFieldHidden('shipping_state') && (
+ {/* State field - conditionally rendered based on API */}
+ {getShippingField('shipping_state') && (
-
State / Province *
+
{getShippingField('shipping_state')?.label || 'State / Province'} {getShippingField('shipping_state')?.required && '*'}
{shippingStateOptions.length > 0 ? (
)}
- {/* Postcode field - hidden if PHP sets type to 'hidden' */}
- {!isFieldHidden('shipping_postcode') && (
+ {/* Postcode field - conditionally rendered based on API */}
+ {getShippingField('shipping_postcode') && (
- Postcode / ZIP *
+ {getShippingField('shipping_postcode')?.label || 'Postcode / ZIP'} {getShippingField('shipping_postcode')?.required && '*'}
setShippingData({ ...shippingData, postcode: e.target.value })}
className="w-full border rounded-lg px-4 py-2"
diff --git a/includes/Api/CheckoutController.php b/includes/Api/CheckoutController.php
index a582c6d..8d933a2 100644
--- a/includes/Api/CheckoutController.php
+++ b/includes/Api/CheckoutController.php
@@ -426,6 +426,23 @@ class CheckoutController {
'taxes' => $rate->get_taxes(),
]);
$order->add_item($item);
+ } elseif (!empty($payload['shipping_cost']) && $payload['shipping_cost'] > 0) {
+ // Fallback: use shipping_cost directly from frontend
+ // This handles API-based shipping like Rajaongkir where WC zones don't apply
+ $item = new \WC_Order_Item_Shipping();
+
+ // Parse method ID from shipping_method (format: "method_id:instance_id" or "method_id:instance_id:variant")
+ $parts = explode(':', $payload['shipping_method']);
+ $method_id = $parts[0] ?? 'shipping';
+ $instance_id = isset($parts[1]) ? (int)$parts[1] : 0;
+
+ $item->set_props([
+ 'method_title' => sanitize_text_field($payload['shipping_title'] ?? 'Shipping'),
+ 'method_id' => sanitize_text_field($method_id),
+ 'instance_id' => $instance_id,
+ 'total' => floatval($payload['shipping_cost']),
+ ]);
+ $order->add_item($item);
}
}