# 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) --- ## 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 '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 ```bash curl "https://yoursite.com/wp-json/woonoow/v1/rajaongkir/destinations?search=bandung" ``` Should return: ```json [ {"value": "1234", "label": "Jawa Barat, Bandung, Kota"}, {"value": "1235", "label": "Jawa Barat, Bandung, Kabupaten"} ] ``` ### 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. Click "Calculate Shipping" or proceed 8. 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: ```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? ```php // Add to the search endpoint error_log('Rajaongkir search: ' . $search); error_log('Results: ' . print_r($results, true)); ``` ### Rajaongkir rates not appearing? 1. Check session is set: ```php 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); ``` 2. Check Rajaongkir debug: - Enable debug in Rajaongkir settings - Check `debug.log` for Rajaongkir messages --- ## Related Documentation - [SHIPPING_INTEGRATION.md](SHIPPING_INTEGRATION.md) - General shipping patterns - [HOOKS_REGISTRY.md](HOOKS_REGISTRY.md) - WooNooW hooks reference