Files
WooNooW/RAJAONGKIR_INTEGRATION.md
Dwindi Ramadhana f518d7e589 feat(checkout): fix searchable select API search and add billing destination
Fixes:
1. SearchableSelect now supports onSearch prop for API-based search
   - Added onSearch and isSearching props
   - shouldFilter disabled when onSearch provided
2. DynamicCheckoutField connects handleApiSearch to SearchableSelect
3. RAJAONGKIR_INTEGRATION.md adds both billing and shipping destination_id

This enables the destination search field to actually call the API
when user types, instead of just filtering local (empty) options.
2026-01-08 14:47:54 +07:00

255 lines
7.5 KiB
Markdown

# Rajaongkir Integration with WooNooW SPA
This guide explains how to integrate Rajaongkir's destination selector with WooNooW's customer checkout SPA.
---
## Prerequisites
Before using this integration:
1. **Rajaongkir Plugin Installed & Active**
2. **WooCommerce Shipping Zone Configured**
- Go to: WC → Settings → Shipping → Zones
- Add Rajaongkir method to your Indonesia zone
3. **Valid API Key** (Check in Rajaongkir settings)
4. **Couriers Selected** (In Rajaongkir settings)
---
## Code Snippet
Add this to **Code Snippets** or **WPCodebox**:
```php
<?php
/**
* Rajaongkir Bridge for WooNooW SPA Checkout
*
* Enables searchable destination field in WooNooW checkout
* and bridges data to Rajaongkir plugin.
*/
// ============================================================
// 1. REST API Endpoint: Search destinations via Rajaongkir API
// ============================================================
add_action('rest_api_init', function() {
register_rest_route('woonoow/v1', '/rajaongkir/destinations', [
'methods' => 'GET',
'callback' => 'woonoow_rajaongkir_search_destinations',
'permission_callback' => '__return_true',
'args' => [
'search' => [
'required' => false,
'type' => 'string',
],
],
]);
});
function woonoow_rajaongkir_search_destinations($request) {
$search = sanitize_text_field($request->get_param('search') ?? '');
if (strlen($search) < 2) {
return [];
}
// Check if Rajaongkir plugin is active
if (!class_exists('Cekongkir_API')) {
return new WP_Error('rajaongkir_missing', 'Rajaongkir plugin not active', ['status' => 400]);
}
// Use Rajaongkir's API class for the search
// NOTE: Method is search_destination_api() not search_destination()
$api = Cekongkir_API::get_instance();
$results = $api->search_destination_api($search);
if (is_wp_error($results)) {
error_log('Rajaongkir search error: ' . $results->get_error_message());
return [];
}
if (!is_array($results)) {
error_log('Rajaongkir search returned non-array: ' . print_r($results, true));
return [];
}
// Format for WooNooW's SearchableSelect component
$formatted = [];
foreach ($results as $r) {
$formatted[] = [
'value' => (string) ($r['id'] ?? ''),
'label' => $r['label'] ?? $r['text'] ?? '',
];
}
// Limit results
return array_slice($formatted, 0, 50);
}
// ============================================================
// 2. Add destination field to checkout fields (both billing and shipping)
// Always add for Indonesia zone (no premature country check)
// ============================================================
add_filter('woocommerce_checkout_fields', function($fields) {
// Check if Rajaongkir is active
if (!class_exists('Cekongkir_API')) {
return $fields;
}
// Check if store sells to Indonesia (check allowed countries)
$allowed = WC()->countries->get_allowed_countries();
if (!isset($allowed['ID'])) {
return $fields;
}
// Destination field definition (reused for billing and shipping)
$destination_field = [
'type' => 'searchable_select',
'label' => __('Destination (Province, City, Subdistrict)', 'woonoow'),
'required' => false, // Frontend will manage this based on country
'priority' => 85,
'class' => ['form-row-wide'],
'placeholder' => __('Search destination...', 'woonoow'),
// WooNooW-specific: API endpoint configuration
'search_endpoint' => '/woonoow/v1/rajaongkir/destinations',
'search_param' => 'search',
'min_chars' => 2,
// Custom attribute to indicate this is for Indonesia only
'custom_attributes' => [
'data-show-for-country' => 'ID',
],
];
// Add to billing (used when "Ship to different address" is NOT checked)
$fields['billing']['billing_destination_id'] = $destination_field;
// Add to shipping (used when "Ship to different address" IS checked)
$fields['shipping']['shipping_destination_id'] = $destination_field;
return $fields;
}, 20); // Priority 20 to run after Rajaongkir's own filter
// ============================================================
// 3. Bridge WooNooW shipping data to Rajaongkir session
// ============================================================
add_action('woonoow/shipping/before_calculate', function($shipping, $items) {
// Set country in WC customer
if (!empty($shipping['country'])) {
WC()->customer->set_shipping_country($shipping['country']);
WC()->customer->set_billing_country($shipping['country']);
}
// Only process for Indonesia
$country = $shipping['country'] ?? WC()->customer->get_shipping_country();
if ($country !== 'ID') {
// Clear destination for non-Indonesia
WC()->session->__unset('selected_destination_id');
WC()->session->__unset('selected_destination_label');
return;
}
// Get destination_id from shipping data (various possible keys)
$destination_id = $shipping['destination_id']
?? $shipping['shipping_destination_id']
?? null;
if (empty($destination_id)) {
return;
}
// Set session for Rajaongkir
WC()->session->set('selected_destination_id', intval($destination_id));
// Also set label if provided
$label = $shipping['destination_label']
?? $shipping['shipping_destination_id_label']
?? '';
if ($label) {
WC()->session->set('selected_destination_label', sanitize_text_field($label));
}
// Clear shipping cache to force recalculation
WC()->session->set('shipping_for_package_0', false);
}, 10, 2);
```
---
## Testing
### 1. Test the API Endpoint
After adding the snippet:
```
GET /wp-json/woonoow/v1/rajaongkir/destinations?search=bandung
```
Should return:
```json
[
{"value": "1234", "label": "Jawa Barat, Bandung, Kota"},
...
]
```
### 2. Test Checkout Flow
1. Add product to cart
2. Go to SPA checkout: `/store/checkout`
3. Set country to Indonesia
4. "Destination" field should appear
5. Type 2+ characters to search
6. Select a destination
7. Rajaongkir rates should appear
---
## Troubleshooting
### API returns empty?
Check `debug.log` for errors:
```php
// Added logging in the search function
error_log('Rajaongkir search error: ...');
```
Common issues:
- Invalid Rajaongkir API key
- Rajaongkir plugin not active
- API quota exceeded
### Field not appearing?
1. Ensure snippet is active
2. Check if store sells to Indonesia
3. Check browser console for JS errors
### Rajaongkir rates not showing?
1. Check session is set:
```php
add_action('woonoow/shipping/before_calculate', function($shipping) {
error_log('Shipping data: ' . print_r($shipping, true));
}, 5);
```
2. Check Rajaongkir is enabled in shipping zone
---
## Known Limitations
1. **Field visibility**: Currently field always shows for checkout. Future improvement: hide in React when country ≠ ID.
2. **Session timing**: Must select destination before calculating shipping.
---
## Related Documentation
- [SHIPPING_INTEGRATION.md](SHIPPING_INTEGRATION.md) - General shipping patterns
- [HOOKS_REGISTRY.md](HOOKS_REGISTRY.md) - WooNooW hooks reference