feat(shipping): searchable state fields and addon hook
1. Admin OrderForm: Changed billing & shipping state from Select to
SearchableSelect for better UX (consistent with country field)
2. OrdersController: Replaced Rajaongkir-specific hardcoded session
handling with generic filter hook:
do_action('woonoow/shipping/before_calculate', $shipping, $items)
3. Added RAJAONGKIR_INTEGRATION.md with:
- Hook documentation
- Code snippet to bridge Rajaongkir with WooNooW
- Frontend integration examples
- Troubleshooting guide
This commit is contained in:
204
RAJAONGKIR_INTEGRATION.md
Normal file
204
RAJAONGKIR_INTEGRATION.md
Normal file
@@ -0,0 +1,204 @@
|
||||
# Rajaongkir Integration with WooNooW
|
||||
|
||||
This guide explains how to bridge the Rajaongkir shipping plugin with WooNooW's admin order form and checkout flow.
|
||||
|
||||
---
|
||||
|
||||
## The Challenge
|
||||
|
||||
Rajaongkir doesn't use standard WooCommerce address fields. Instead of using `city` and `state`, it requires a **destination ID** from its own Indonesian location database.
|
||||
|
||||
**Standard WooCommerce Flow:**
|
||||
```
|
||||
Country → State → City → Postcode
|
||||
```
|
||||
|
||||
**Rajaongkir Flow:**
|
||||
```
|
||||
Country (ID) → Destination ID (subdistrict level)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## WooNooW Integration Hook
|
||||
|
||||
WooNooW provides a hook that fires **before** shipping calculation. This allows plugins like Rajaongkir to set session variables or prepare any data they need.
|
||||
|
||||
### Hook: `woonoow/shipping/before_calculate`
|
||||
|
||||
```php
|
||||
do_action( 'woonoow/shipping/before_calculate', $shipping_data, $items );
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `$shipping_data` (array) - The shipping address from frontend:
|
||||
- `country` - Country code (e.g., 'ID')
|
||||
- `state` - State code
|
||||
- `city` - City name
|
||||
- `postcode` - Postal code
|
||||
- `address_1` - Street address
|
||||
- `address_2` - Additional address (optional)
|
||||
- + Any custom fields added by addons
|
||||
- `$items` (array) - Cart items being shipped
|
||||
|
||||
---
|
||||
|
||||
## Code Snippet: Rajaongkir Bridge
|
||||
|
||||
Add this code to your theme's `functions.php` or via a code snippets plugin:
|
||||
|
||||
```php
|
||||
<?php
|
||||
/**
|
||||
* Bridge Rajaongkir plugin with WooNooW shipping calculation.
|
||||
*
|
||||
* This code listens for WooNooW's shipping hook and sets the
|
||||
* Rajaongkir session variables it needs to calculate rates.
|
||||
*/
|
||||
add_action( 'woonoow/shipping/before_calculate', function( $shipping, $items ) {
|
||||
// Only process for Indonesia
|
||||
if ( empty( $shipping['country'] ) || $shipping['country'] !== 'ID' ) {
|
||||
// Clear Rajaongkir session for non-ID countries
|
||||
WC()->session->__unset( 'selected_destination_id' );
|
||||
WC()->session->__unset( 'selected_destination_label' );
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if destination_id is provided by frontend
|
||||
if ( ! empty( $shipping['destination_id'] ) ) {
|
||||
WC()->session->set( 'selected_destination_id', $shipping['destination_id'] );
|
||||
WC()->session->set( 'selected_destination_label', $shipping['destination_label'] ?? $shipping['city'] );
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback: Try to lookup destination from city name
|
||||
// This requires the Rajaongkir database lookup
|
||||
$destination = rajaongkir_lookup_destination( $shipping['city'], $shipping['state'] );
|
||||
if ( $destination ) {
|
||||
WC()->session->set( 'selected_destination_id', $destination['id'] );
|
||||
WC()->session->set( 'selected_destination_label', $destination['label'] );
|
||||
}
|
||||
}, 10, 2 );
|
||||
|
||||
/**
|
||||
* Helper: Lookup Rajaongkir destination by city/state name.
|
||||
*
|
||||
* This is a simplified example. Implement based on your Rajaongkir data structure.
|
||||
*/
|
||||
function rajaongkir_lookup_destination( $city, $state ) {
|
||||
// Query the Rajaongkir location database
|
||||
// This depends on how your Rajaongkir plugin stores location data
|
||||
|
||||
// Example using transient/option storage:
|
||||
$locations = get_option( 'cekongkir_destinations', [] );
|
||||
|
||||
foreach ( $locations as $location ) {
|
||||
if (
|
||||
stripos( $location['city'], $city ) !== false ||
|
||||
stripos( $location['district'], $city ) !== false
|
||||
) {
|
||||
return [
|
||||
'id' => $location['id'],
|
||||
'label' => $location['label'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Frontend Integration (Optional)
|
||||
|
||||
To add a proper Rajaongkir destination selector to WooNooW's admin order form, you need to:
|
||||
|
||||
### 1. Register Custom Address Fields
|
||||
|
||||
```php
|
||||
add_filter( 'woonoow/checkout/address_fields', function( $fields ) {
|
||||
// Only for Indonesia
|
||||
if ( WC()->customer && WC()->customer->get_shipping_country() === 'ID' ) {
|
||||
$fields['destination_id'] = [
|
||||
'type' => 'hidden',
|
||||
'required' => true,
|
||||
];
|
||||
$fields['destination_selector'] = [
|
||||
'type' => 'custom',
|
||||
'component' => 'RajaongkirDestinationSelector',
|
||||
'label' => __( 'Destination', 'woonoow-rajaongkir' ),
|
||||
'required' => true,
|
||||
];
|
||||
}
|
||||
return $fields;
|
||||
} );
|
||||
```
|
||||
|
||||
### 2. Enqueue JavaScript for Destination Search
|
||||
|
||||
```php
|
||||
add_action( 'woonoow/admin/enqueue_scripts', function() {
|
||||
wp_enqueue_script(
|
||||
'woonoow-rajaongkir',
|
||||
plugins_url( 'assets/js/woonoow-integration.js', __FILE__ ),
|
||||
[ 'woonoow-admin' ],
|
||||
'1.0.0',
|
||||
true
|
||||
);
|
||||
|
||||
wp_localize_script( 'woonoow-rajaongkir', 'WNW_RAJAONGKIR', [
|
||||
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
|
||||
'nonce' => wp_create_nonce( 'rajaongkir_search' ),
|
||||
] );
|
||||
} );
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
1. Install and configure Rajaongkir plugin
|
||||
2. Add the code snippet above
|
||||
3. Go to WooNooW → Orders → Create New Order
|
||||
4. Add a product
|
||||
5. Set country to Indonesia
|
||||
6. Fill in city/state (or use destination selector if implemented)
|
||||
7. Click "Calculate Shipping"
|
||||
8. Verify Rajaongkir rates appear
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Rates not appearing?
|
||||
|
||||
1. Check browser DevTools Network tab for `/shipping/calculate` response
|
||||
2. Look for `debug` object in response:
|
||||
```json
|
||||
{
|
||||
"methods": [...],
|
||||
"debug": {
|
||||
"packages_count": 1,
|
||||
"cart_items_count": 1,
|
||||
"address": { ... }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Verify Rajaongkir session is set:
|
||||
```php
|
||||
error_log( 'destination_id: ' . WC()->session->get( 'selected_destination_id' ) );
|
||||
```
|
||||
|
||||
### Session not persisting?
|
||||
|
||||
Make sure WooCommerce session is initialized before the hook runs. The hook fires during REST API calls where session may not be initialized by default.
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [SHIPPING_INTEGRATION.md](SHIPPING_INTEGRATION.md) - General shipping integration guide
|
||||
- [SHIPPING_METHOD_TYPES.md](SHIPPING_METHOD_TYPES.md) - Shipping method types explanation
|
||||
- [Rajaongkir Plugin Documentation](https://cekongkir.com/docs)
|
||||
@@ -1126,16 +1126,13 @@ export default function OrderForm({
|
||||
</div>
|
||||
<div>
|
||||
<Label>{__('State/Province')}</Label>
|
||||
<Select value={bState} onValueChange={setBState}>
|
||||
<SelectTrigger className="w-full"><SelectValue placeholder={__('Select state')} /></SelectTrigger>
|
||||
<SelectContent className="max-h-64">
|
||||
{bStateOptions.length ? bStateOptions.map(o => (
|
||||
<SelectItem key={o.value} value={o.value}>{o.label}</SelectItem>
|
||||
)) : (
|
||||
<SelectItem value="__none__" disabled>{__('N/A')}</SelectItem>
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<SearchableSelect
|
||||
options={bStateOptions}
|
||||
value={bState}
|
||||
onChange={setBState}
|
||||
placeholder={bStateOptions.length ? __('Select state') : __('N/A')}
|
||||
disabled={!bStateOptions.length}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
@@ -1177,7 +1174,7 @@ export default function OrderForm({
|
||||
{field.label}
|
||||
{field.required && <span className="text-destructive ml-1">*</span>}
|
||||
</Label>
|
||||
{field.type === 'select' && field.options ? (
|
||||
{field.type === 'select' && field.options && field.key !== 'shipping_state' ? (
|
||||
<Select
|
||||
value={shippingData[fieldKey] || ''}
|
||||
onValueChange={(v) => setShippingData({ ...shippingData, [fieldKey]: v })}
|
||||
@@ -1199,6 +1196,14 @@ export default function OrderForm({
|
||||
placeholder={field.placeholder || __('Select country')}
|
||||
disabled={oneCountryOnly}
|
||||
/>
|
||||
) : field.key === 'shipping_state' && field.options ? (
|
||||
<SearchableSelect
|
||||
options={Object.entries(field.options).map(([value, label]: [string, any]) => ({ value, label }))}
|
||||
value={shippingData.state || ''}
|
||||
onChange={(v) => setShippingData({ ...shippingData, state: v })}
|
||||
placeholder={field.placeholder || __('Select state')}
|
||||
disabled={!Object.keys(field.options).length}
|
||||
/>
|
||||
) : field.type === 'textarea' ? (
|
||||
<Textarea
|
||||
value={shippingData[fieldKey] || ''}
|
||||
|
||||
@@ -1485,16 +1485,18 @@ class OrdersController {
|
||||
WC()->customer->set_billing_postcode( $postcode );
|
||||
WC()->customer->set_billing_city( $city );
|
||||
|
||||
// Support for Rajaongkir plugin - set destination in session
|
||||
// Rajaongkir uses session-based destination instead of standard address fields
|
||||
if ( $country === 'ID' && ! empty( $shipping['destination_id'] ) ) {
|
||||
WC()->session->set( 'selected_destination_id', $shipping['destination_id'] );
|
||||
WC()->session->set( 'selected_destination_label', $shipping['destination_label'] ?? $city );
|
||||
} else {
|
||||
// Clear Rajaongkir session data for non-ID countries
|
||||
WC()->session->__unset( 'selected_destination_id' );
|
||||
WC()->session->__unset( 'selected_destination_label' );
|
||||
}
|
||||
/**
|
||||
* Allow shipping addons to prepare session/data before shipping calculation.
|
||||
*
|
||||
* This hook allows third-party shipping plugins (like Rajaongkir, Biteship, etc.)
|
||||
* to set any session variables or prepare data they need before WooCommerce
|
||||
* calculates shipping rates.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param array $shipping The shipping address data from frontend (country, state, city, postcode, address_1, etc.)
|
||||
* @param array $items The cart items being shipped
|
||||
*/
|
||||
do_action( 'woonoow/shipping/before_calculate', $shipping, $items ?? [] );
|
||||
}
|
||||
|
||||
// Calculate shipping
|
||||
|
||||
Reference in New Issue
Block a user