315 lines
13 KiB
PHP
315 lines
13 KiB
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) < 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);
|