## Discovery ✅ Rajaongkir plugin uses a completely different approach: - Removes standard WooCommerce city/state fields - Adds custom destination dropdown with Select2 search - Stores destination in WooCommerce session (not address fields) - Reads from session during shipping calculation ## Root Cause of Issues: ### 1. Same rates for different provinces - OrderForm sends: city="Bandung", state="Jawa Barat" - Rajaongkir ignores these fields - Rajaongkir reads: WC()->session->get("selected_destination_id") - Session empty → Uses cached/default rates ### 2. No Rajaongkir API hits - No destination_id in session - Rajaongkir can't calculate without destination - Returns empty or cached rates ## Backend Fix (✅ DONE): Added Rajaongkir session support in calculate_shipping: ```php // Support for Rajaongkir plugin if ( $country === 'ID' && ! empty( $shipping['destination_id'] ) ) { WC()->session->set( 'selected_destination_id', $shipping['destination_id'] ); WC()->session->set( 'selected_destination_label', $shipping['destination_label'] ); } ``` ## Frontend Fix (TODO): Need to add Rajaongkir destination field: 1. Add destination search component (Select2/Combobox) 2. Search Rajaongkir API for locations 3. Pass destination_id to backend 4. Backend sets session before calculate_shipping() ## Documentation: Created RAJAONGKIR_INTEGRATION.md with: - How Rajaongkir works - Why our implementation fails - Complete solution steps - Testing checklist ## Next Steps: 1. Add Rajaongkir search endpoint to OrdersController 2. Create destination search component in OrderForm 3. Pass destination_id in shipping data 4. Test with real Rajaongkir API
5.7 KiB
5.7 KiB
Rajaongkir Integration Issue
Problem Discovery
Rajaongkir plugin doesn't use standard WooCommerce address fields for Indonesian shipping calculation.
How Rajaongkir Works:
-
Removes Standard Fields:
// class-cekongkir.php line 645 public function customize_checkout_fields($fields) { unset($fields['billing']['billing_state']); unset($fields['billing']['billing_city']); unset($fields['shipping']['shipping_state']); unset($fields['shipping']['shipping_city']); return $fields; } -
Adds Custom Destination Dropdown:
// Adds Select2 dropdown for searching locations <select id="cart-destination" name="cart_destination"> <option>Search and select location...</option> </select> -
Stores in Session:
// When user selects destination via AJAX WC()->session->set('selected_destination_id', $destination_id); WC()->session->set('selected_destination_label', $destination_label); -
Triggers Shipping Calculation:
// After destination selected WC()->cart->calculate_shipping(); WC()->cart->calculate_totals();
Why Our Implementation Fails:
OrderForm.tsx:
- Uses standard fields:
city,state,postcode - Rajaongkir ignores these fields
- Rajaongkir only reads from session:
selected_destination_id
Backend API:
- Sets
WC()->customer->set_shipping_city($city) - Rajaongkir doesn't use this
- Rajaongkir reads:
WC()->session->get('selected_destination_id')
Result:
- Same rates for all provinces ❌
- No Rajaongkir API hits ❌
- Shipping calculation fails ❌
Solution
Backend (✅ DONE):
// OrdersController.php - calculate_shipping method
if ( $country === 'ID' && ! empty( $shipping['destination_id'] ) ) {
WC()->session->set( 'selected_destination_id', $shipping['destination_id'] );
WC()->session->set( 'selected_destination_label', $shipping['destination_label'] );
}
Frontend (TODO):
Need to add Rajaongkir destination field to OrderForm.tsx:
-
Add Destination Search Field:
// For Indonesia only {bCountry === 'ID' && ( <div> <Label>Destination</Label> <DestinationSearch value={destinationId} onChange={(id, label) => { setDestinationId(id); setDestinationLabel(label); }} /> </div> )} -
Pass to API:
shipping: { country: bCountry, state: bState, city: bCity, destination_id: destinationId, // For Rajaongkir destination_label: destinationLabel // For Rajaongkir } -
API Endpoint:
// Add search endpoint GET /woonoow/v1/rajaongkir/search?query=bandung // Proxy to Rajaongkir API POST /wp-admin/admin-ajax.php action=cart_search_destination query=bandung
Rajaongkir Destination Format
Destination ID Examples:
city:23- City ID 23 (Bandung)subdistrict:456- Subdistrict ID 456province:9- Province ID 9 (Jawa Barat)
API Response:
{
"success": true,
"data": [
{
"id": "city:23",
"text": "Bandung, Jawa Barat"
},
{
"id": "subdistrict:456",
"text": "Bandung Wetan, Bandung, Jawa Barat"
}
]
}
Implementation Steps
Step 1: Add Rajaongkir Search Endpoint (Backend)
// OrdersController.php
public static function search_rajaongkir_destination( WP_REST_Request $req ) {
$query = sanitize_text_field( $req->get_param( 'query' ) );
// Call Rajaongkir API
$api = Cekongkir_API::get_instance();
$results = $api->search_destination_api( $query );
return new \WP_REST_Response( $results, 200 );
}
Step 2: Add Destination Field (Frontend)
// OrderForm.tsx
const [destinationId, setDestinationId] = useState('');
const [destinationLabel, setDestinationLabel] = useState('');
// Add to shipping data
const effectiveShippingAddress = useMemo(() => {
return {
country: bCountry,
state: bState,
city: bCity,
destination_id: destinationId,
destination_label: destinationLabel,
};
}, [bCountry, bState, bCity, destinationId, destinationLabel]);
Step 3: Create Destination Search Component
// components/RajaongkirDestinationSearch.tsx
export function RajaongkirDestinationSearch({ value, onChange }) {
const [query, setQuery] = useState('');
const { data: results } = useQuery({
queryKey: ['rajaongkir-search', query],
queryFn: () => api.get(`/rajaongkir/search?query=${query}`),
enabled: query.length >= 3,
});
return (
<Combobox value={value} onChange={onChange}>
<ComboboxInput onChange={(e) => setQuery(e.target.value)} />
<ComboboxOptions>
{results?.map(r => (
<ComboboxOption key={r.id} value={r.id}>
{r.text}
</ComboboxOption>
))}
</ComboboxOptions>
</Combobox>
);
}
Testing
Before Fix:
- Select "Jawa Barat" → JNE REG Rp31,000
- Select "Bali" → JNE REG Rp31,000 (wrong! cached)
- Rajaongkir dashboard → 0 API hits
After Fix:
- Search "Bandung" → Select "Bandung, Jawa Barat"
- ✅ Rajaongkir API hit
- ✅ Returns: JNE REG Rp31,000, JNE YES Rp42,000
- Search "Denpasar" → Select "Denpasar, Bali"
- ✅ Rajaongkir API hit
- ✅ Returns: JNE REG Rp45,000, JNE YES Rp58,000 (different!)
Notes
- Rajaongkir is Indonesia-specific (country === 'ID')
- For other countries, use standard WooCommerce fields
- Destination ID format:
type:id(e.g.,city:23,subdistrict:456) - Session data is critical - must be set before
calculate_shipping() - Frontend needs autocomplete/search component (Select2 or similar)