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.
255 lines
7.5 KiB
Markdown
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
|