'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 and hide redundant fields for Indonesia // The destination_id from Rajaongkir contains province/city/subdistrict // ============================================================ 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; } // Check if Indonesia is the ONLY allowed country $indonesia_only = count($allowed) === 1 && isset($allowed['ID']); // If Indonesia only, hide country/state/city fields (Rajaongkir destination has all this) if ($indonesia_only) { // Hide billing fields if (isset($fields['billing']['billing_last_name'])) { $fields['billing']['billing_last_name']['type'] = 'hidden'; $fields['billing']['billing_last_name']['default'] = 'ID'; $fields['billing']['billing_last_name']['required'] = false; // Make first_name take full width since last_name is hidden if (isset($fields['billing']['billing_first_name'])) { $fields['billing']['billing_first_name']['class'] = ['form-row-wide']; } } if (isset($fields['billing']['billing_country'])) { $fields['billing']['billing_country']['type'] = 'hidden'; $fields['billing']['billing_country']['default'] = 'ID'; $fields['billing']['billing_country']['required'] = false; } if (isset($fields['billing']['billing_state'])) { $fields['billing']['billing_state']['type'] = 'hidden'; $fields['billing']['billing_state']['required'] = false; } if (isset($fields['billing']['billing_city'])) { $fields['billing']['billing_city']['type'] = 'hidden'; $fields['billing']['billing_city']['required'] = false; } if (isset($fields['billing']['billing_postcode'])) { $fields['billing']['billing_postcode']['type'] = 'hidden'; $fields['billing']['billing_postcode']['required'] = false; } // Hide shipping fields if (isset($fields['shipping']['shipping_last_name'])) { $fields['shipping']['shipping_last_name']['type'] = 'hidden'; $fields['shipping']['shipping_last_name']['default'] = 'ID'; $fields['shipping']['shipping_last_name']['required'] = false; // Make first_name take full width since last_name is hidden if (isset($fields['shipping']['shipping_first_name'])) { $fields['shipping']['shipping_first_name']['class'] = ['form-row-wide']; } } if (isset($fields['shipping']['shipping_country'])) { $fields['shipping']['shipping_country']['type'] = 'hidden'; $fields['shipping']['shipping_country']['default'] = 'ID'; $fields['shipping']['shipping_country']['required'] = false; } if (isset($fields['shipping']['shipping_state'])) { $fields['shipping']['shipping_state']['type'] = 'hidden'; $fields['shipping']['shipping_state']['required'] = false; } if (isset($fields['shipping']['shipping_city'])) { $fields['shipping']['shipping_city']['type'] = 'hidden'; $fields['shipping']['shipping_city']['required'] = false; } if (isset($fields['shipping']['shipping_postcode'])) { $fields['shipping']['shipping_postcode']['type'] = 'hidden'; $fields['shipping']['shipping_postcode']['required'] = false; } } // Check if cart needs shipping $needs_shipping = true; // If cart is empty, we assume it's for Address Book in My Account where we want fields visible if (function_exists('WC') && WC()->cart && !WC()->cart->is_empty()) { $needs_shipping = WC()->cart->needs_shipping(); } // Destination field definition (reused for billing and shipping) $destination_field = [ 'type' => $needs_shipping ? 'searchable_select' : 'hidden', 'label' => __('Destination (Province, City, Subdistrict)', 'woonoow'), 'required' => $indonesia_only && $needs_shipping, // Required if Indonesia only and needs shipping '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 // Sets destination_id in WC session for Rajaongkir to use // ============================================================ add_action('woonoow/shipping/before_calculate', function ($shipping, $items) { // Check if Rajaongkir is active if (!class_exists('Cekongkir_API')) { return; } // For Indonesia-only stores, always set country to ID $allowed = WC()->countries->get_allowed_countries(); $indonesia_only = count($allowed) === 1 && isset($allowed['ID']); if ($indonesia_only) { WC()->customer->set_shipping_country('ID'); WC()->customer->set_billing_country('ID'); } elseif (!empty($shipping['country'])) { WC()->customer->set_shipping_country($shipping['country']); WC()->customer->set_billing_country($shipping['country']); } // Only process Rajaongkir 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'] ?? $shipping['billing_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'] ?? $shipping['billing_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); // ============================================================ // 4. Save destination_id to Order Meta on SPA Checkout // ============================================================ add_action('woocommerce_checkout_order_processed', function ($order_id, $payload) { // Extract and save destination_id from shipping payload if (!empty($payload['shipping']['destination_id'])) { update_post_meta($order_id, '_shipping_destination_id', sanitize_text_field($payload['shipping']['destination_id'])); } // Extract and save destination_id from billing payload if (!empty($payload['billing']['destination_id'])) { update_post_meta($order_id, '_billing_destination_id', sanitize_text_field($payload['billing']['destination_id'])); } // Fallback to custom_fields array if present if (!empty($payload['custom_fields']['shipping_destination_id'])) { update_post_meta($order_id, '_shipping_destination_id', sanitize_text_field($payload['custom_fields']['shipping_destination_id'])); } if (!empty($payload['custom_fields']['billing_destination_id'])) { update_post_meta($order_id, '_billing_destination_id', sanitize_text_field($payload['custom_fields']['billing_destination_id'])); } // Save labels too if they exist, useful for backend viewing if (!empty($payload['custom_fields']['shipping_destination_id_label'])) { update_post_meta($order_id, '_shipping_destination_id_label', sanitize_text_field($payload['custom_fields']['shipping_destination_id_label'])); } if (!empty($payload['custom_fields']['billing_destination_id_label'])) { update_post_meta($order_id, '_billing_destination_id_label', sanitize_text_field($payload['custom_fields']['billing_destination_id_label'])); } }, 10, 2); // ============================================================ // 5. Format address display for SPA saved addresses // ============================================================ add_filter('woonoow_format_address', function ($formatted, $address) { // If a snippet has already formatted it, skip if (!empty($formatted)) { return $formatted; } $type = $address['type'] ?? 'billing'; $is_billing = $type === 'billing' || $type === 'both'; // Look for destination_id_label $label = ''; if (!empty($address['destination_id_label'])) { $label = $address['destination_id_label']; } elseif ($is_billing && !empty($address['billing_destination_id_label'])) { $label = $address['billing_destination_id_label']; } elseif (!$is_billing && !empty($address['shipping_destination_id_label'])) { $label = $address['shipping_destination_id_label']; } // If we have a Rajaongkir label, construct a clean Indonesian address if ($label) { $parts = []; if (!empty($address['address_1'])) { $parts[] = $address['address_1']; } if (!empty($address['address_2'])) { $parts[] = $address['address_2']; } // Append the Rajaongkir province/city/subdistrict string $parts[] = $label; if (!empty($address['postcode'])) { $parts[] = $address['postcode']; } // The SPA uses whitespace-pre-wrap so newline \n works for visual separation return implode("\n", $parts); } return $formatted; }, 10, 2);