# 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 '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) < 3) { 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 // NOTE: Path is relative to /wp-json/woonoow/v1 'search_endpoint' => '/rajaongkir/destinations', 'search_param' => 'search', 'min_chars' => 3, // 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