docs: update Rajaongkir snippet and add generic shipping bridge pattern
RAJAONGKIR_INTEGRATION.md: - Hide country/state/city when Indonesia is the only allowed country - Make destination_id required for Indonesia-only stores - Force country to ID in session bridge - Added billing_destination_id fallback SHIPPING_BRIDGE_PATTERN.md: - New generic template for shipping provider integrations - Documents architecture, hooks, and field types - Provides copy-paste template for new providers - Includes checklist for new integrations
This commit is contained in:
219
SHIPPING_BRIDGE_PATTERN.md
Normal file
219
SHIPPING_BRIDGE_PATTERN.md
Normal file
@@ -0,0 +1,219 @@
|
||||
# WooNooW Shipping Bridge Pattern
|
||||
|
||||
This document describes a generic pattern for integrating any external shipping API with WooNooW's SPA checkout.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
WooNooW provides hooks and endpoints that allow any shipping plugin to:
|
||||
1. **Register custom checkout fields** (searchable selects, dropdowns, etc.)
|
||||
2. **Bridge data to the plugin's session/API** before shipping calculation
|
||||
3. **Display live rates** from external APIs
|
||||
|
||||
This pattern is NOT specific to Rajaongkir - it can be used for any shipping provider.
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ WooNooW Customer SPA │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ 1. Checkout loads → calls /checkout/fields │
|
||||
│ 2. Renders custom fields (e.g., searchable destination) │
|
||||
│ 3. User fills form → calls /checkout/shipping-rates │
|
||||
│ 4. Hook triggers → shipping plugin calculates rates │
|
||||
│ 5. Rates displayed → user selects → order submitted │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Your Bridge Snippet │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ • woocommerce_checkout_fields → Add custom fields │
|
||||
│ • register_rest_route → API endpoint for field data │
|
||||
│ • woonoow/shipping/before_calculate → Set session/data │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Shipping Plugin (Any) │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ • Reads from WC session or customer data │
|
||||
│ • Calls external API (Rajaongkir, Sicepat, JNE, etc.) │
|
||||
│ • Returns rates via get_rates_for_package() │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Generic Bridge Template
|
||||
|
||||
```php
|
||||
<?php
|
||||
/**
|
||||
* [PROVIDER_NAME] Bridge for WooNooW SPA Checkout
|
||||
*
|
||||
* Replace [PROVIDER_NAME], [PROVIDER_CLASS], and [PROVIDER_SESSION_KEY]
|
||||
* with your shipping plugin's specifics.
|
||||
*/
|
||||
|
||||
// ============================================================
|
||||
// 1. REST API Endpoint: Search/fetch data from provider
|
||||
// ============================================================
|
||||
add_action('rest_api_init', function() {
|
||||
register_rest_route('woonoow/v1', '/[provider]/search', [
|
||||
'methods' => 'GET',
|
||||
'callback' => 'woonoow_[provider]_search',
|
||||
'permission_callback' => '__return_true', // Public for customer use
|
||||
'args' => [
|
||||
'search' => ['type' => 'string', 'required' => false],
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
function woonoow_[provider]_search($request) {
|
||||
$search = sanitize_text_field($request->get_param('search') ?? '');
|
||||
|
||||
if (strlen($search) < 3) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Check if plugin is active
|
||||
if (!class_exists('[PROVIDER_CLASS]')) {
|
||||
return new WP_Error('[provider]_missing', 'Plugin not active', ['status' => 400]);
|
||||
}
|
||||
|
||||
// Call provider's API
|
||||
// $results = [PROVIDER_CLASS]::search($search);
|
||||
|
||||
// Format for WooNooW's SearchableSelect
|
||||
$formatted = [];
|
||||
foreach ($results as $r) {
|
||||
$formatted[] = [
|
||||
'value' => (string) $r['id'],
|
||||
'label' => $r['name'],
|
||||
];
|
||||
}
|
||||
|
||||
return array_slice($formatted, 0, 50);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 2. Add custom field(s) to checkout
|
||||
// ============================================================
|
||||
add_filter('woocommerce_checkout_fields', function($fields) {
|
||||
if (!class_exists('[PROVIDER_CLASS]')) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$custom_field = [
|
||||
'type' => 'searchable_select', // or 'select', 'text'
|
||||
'label' => __('[Field Label]', 'woonoow'),
|
||||
'required' => true,
|
||||
'priority' => 85,
|
||||
'class' => ['form-row-wide'],
|
||||
'placeholder' => __('Search...', 'woonoow'),
|
||||
'search_endpoint' => '/[provider]/search', // Relative to /wp-json/woonoow/v1
|
||||
'search_param' => 'search',
|
||||
'min_chars' => 3,
|
||||
];
|
||||
|
||||
$fields['billing']['billing_[provider]_field'] = $custom_field;
|
||||
$fields['shipping']['shipping_[provider]_field'] = $custom_field;
|
||||
|
||||
return $fields;
|
||||
}, 20);
|
||||
|
||||
// ============================================================
|
||||
// 3. Bridge data to provider before shipping calculation
|
||||
// ============================================================
|
||||
add_action('woonoow/shipping/before_calculate', function($shipping, $items) {
|
||||
if (!class_exists('[PROVIDER_CLASS]')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get custom field value from shipping data
|
||||
$field_value = $shipping['[provider]_field']
|
||||
?? $shipping['shipping_[provider]_field']
|
||||
?? $shipping['billing_[provider]_field']
|
||||
?? null;
|
||||
|
||||
if (empty($field_value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set in WC session for the shipping plugin to use
|
||||
WC()->session->set('[PROVIDER_SESSION_KEY]', $field_value);
|
||||
|
||||
// Clear shipping cache to force recalculation
|
||||
WC()->session->set('shipping_for_package_0', false);
|
||||
|
||||
}, 10, 2);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Supported Field Types
|
||||
|
||||
| Type | Description | Use Case |
|
||||
|------|-------------|----------|
|
||||
| `searchable_select` | Dropdown with API search | Destinations, locations, service points |
|
||||
| `select` | Static dropdown | Service types, delivery options |
|
||||
| `text` | Free text input | Reference numbers, notes |
|
||||
| `hidden` | Hidden field | Default values, auto-set data |
|
||||
|
||||
---
|
||||
|
||||
## WooNooW Hooks Reference
|
||||
|
||||
| Hook | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `woonoow/shipping/before_calculate` | Action | Called before shipping rates are calculated |
|
||||
| `woocommerce_checkout_fields` | Filter | Standard WC filter for checkout fields |
|
||||
|
||||
---
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Sicepat Integration
|
||||
```php
|
||||
// Endpoint
|
||||
register_rest_route('woonoow/v1', '/sicepat/destinations', ...);
|
||||
|
||||
// Session key
|
||||
WC()->session->set('sicepat_destination_code', $code);
|
||||
```
|
||||
|
||||
### Example 2: JNE Direct API
|
||||
```php
|
||||
// Endpoint for origin selection
|
||||
register_rest_route('woonoow/v1', '/jne/origins', ...);
|
||||
register_rest_route('woonoow/v1', '/jne/destinations', ...);
|
||||
|
||||
// Multiple session keys
|
||||
WC()->session->set('jne_origin', $origin);
|
||||
WC()->session->set('jne_destination', $destination);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Checklist for New Integration
|
||||
|
||||
- [ ] Identify the shipping plugin's class name
|
||||
- [ ] Find what session/data it reads for API calls
|
||||
- [ ] Create REST endpoint for searchable data
|
||||
- [ ] Add checkout field(s) via filter
|
||||
- [ ] Bridge data via `woonoow/shipping/before_calculate`
|
||||
- [ ] Test shipping rate calculation
|
||||
- [ ] Document in dedicated `[PROVIDER]_INTEGRATION.md`
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [RAJAONGKIR_INTEGRATION.md](RAJAONGKIR_INTEGRATION.md) - Rajaongkir-specific implementation
|
||||
- [SHIPPING_INTEGRATION.md](SHIPPING_INTEGRATION.md) - General shipping patterns
|
||||
- [HOOKS_REGISTRY.md](HOOKS_REGISTRY.md) - All WooNooW hooks
|
||||
Reference in New Issue
Block a user