Based on deep analysis of Rajaongkir plugin: - Destinations searched via RajaOngkir API (no local DB table) - Uses Cekongkir_API::search_destination() for search - Session 'selected_destination_id' required for rates - Added SPA-aware checkout field injection Code snippet includes: 1. REST endpoint /woonoow/v1/rajaongkir/destinations 2. Checkout field filter with REST context detection 3. Session bridge via woonoow/shipping/before_calculate
9.1 KiB
9.1 KiB
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:
- Rajaongkir Plugin Installed & Active
- WooCommerce Shipping Zone Configured
- Go to: WC → Settings → Shipping → Zones
- Add Rajaongkir method to your Indonesia zone
- Valid API Key (Check in Rajaongkir settings)
- Couriers Selected (In Rajaongkir settings)
How It Works
┌─────────────────┐ ┌───────────────────┐ ┌──────────────────┐
│ Customer types │ → │ /rajaongkir/ │ → │ SearchableSelect │
│ "Bandung" │ │ destinations API │ │ shows results │
└─────────────────┘ └───────────────────┘ └──────────────────┘
│
▼
┌─────────────────┐ ┌───────────────────┐ ┌──────────────────┐
│ Rajaongkir uses │ ← │ Hook sets WC │ ← │ Customer selects │
│ session to get │ │ session data │ │ destination │
│ shipping rates │ │ │ │ │
└─────────────────┘ └───────────────────┘ └──────────────────┘
Code Snippet
Add this to Code Snippets or WPCodebox:
<?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
$api = Cekongkir_API::get_instance();
$results = $api->search_destination(['keyword' => $search]);
if (is_wp_error($results)) {
return [];
}
// Format for WooNooW's SearchableSelect component
$formatted = [];
foreach ($results as $r) {
$formatted[] = [
'value' => (string) $r['id'],
'label' => $r['label'], // "Province, City, District"
];
}
// Limit results
return array_slice($formatted, 0, 50);
}
// ============================================================
// 2. Add destination field to checkout fields (SPA-aware)
// ============================================================
add_filter('woocommerce_checkout_fields', function($fields) {
// Check if Rajaongkir is active
if (!class_exists('Cekongkir_API')) {
return $fields;
}
// Get country from various sources
$country = '';
// From WC customer object
if (WC()->customer) {
$country = WC()->customer->get_shipping_country();
}
// From REST API request body (for SPA context)
if (defined('REST_REQUEST') && REST_REQUEST) {
$json = file_get_contents('php://input');
if ($json) {
$data = json_decode($json, true);
if (isset($data['shipping']['country'])) {
$country = $data['shipping']['country'];
}
}
}
// Only add field for Indonesia or when country not yet determined
if ($country && $country !== 'ID') {
return $fields;
}
// Add searchable destination field
$fields['shipping']['shipping_destination_id'] = [
'type' => 'searchable_select',
'label' => __('Destination (Province, City, Subdistrict)', 'woonoow'),
'required' => true,
'priority' => 85, // After country/state, before postcode
'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,
];
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)) {
// No destination selected yet
return;
}
// Set session for Rajaongkir
WC()->session->set('selected_destination_id', intval($destination_id));
// Also set label if provided (for display purposes)
$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);
Field Configuration Options
The searchable_select field type supports:
| Option | Description |
|---|---|
type |
'searchable_select' for API-backed search |
search_endpoint |
REST API endpoint path |
search_param |
Query parameter name (default: 'search') |
min_chars |
Minimum characters before search (default: 2) |
placeholder |
Input placeholder text |
Testing
1. Test the API Endpoint
curl "https://yoursite.com/wp-json/woonoow/v1/rajaongkir/destinations?search=bandung"
Should return:
[
{"value": "1234", "label": "Jawa Barat, Bandung, Kota"},
{"value": "1235", "label": "Jawa Barat, Bandung, Kabupaten"}
]
2. Test Checkout Flow
- Add product to cart
- Go to SPA checkout:
/store/checkout - Set country to Indonesia
- "Destination" field should appear
- Type 2+ characters to search
- Select a destination
- Click "Calculate Shipping" or proceed
- Rajaongkir rates should appear
Troubleshooting
Destination field not appearing?
Check if:
- Country is set to Indonesia
- Rajaongkir plugin is active
- Snippet has no syntax errors
Debug in PHP:
add_action('woocommerce_checkout_init', function() {
$fields = WC()->checkout()->get_checkout_fields();
error_log('Shipping fields: ' . print_r(array_keys($fields['shipping'] ?? []), true));
});
Search returns empty?
// Add to the search endpoint
error_log('Rajaongkir search: ' . $search);
error_log('Results: ' . print_r($results, true));
Rajaongkir rates not appearing?
- Check session is set:
add_action('woonoow/shipping/before_calculate', function($shipping) {
error_log('Destination ID in shipping data: ' . print_r($shipping, true));
error_log('Session destination: ' . WC()->session->get('selected_destination_id'));
}, 5);
- Check Rajaongkir debug:
- Enable debug in Rajaongkir settings
- Check
debug.logfor Rajaongkir messages
Related Documentation
- SHIPPING_INTEGRATION.md - General shipping patterns
- HOOKS_REGISTRY.md - WooNooW hooks reference