fix: Critical fixes for shipping and meta field registration
Issue 1: Shipping recalculation on order edit (FIXED) - Problem: OrderForm recalculated shipping on every edit - Expected: Shipping should be fixed unless address changes - Solution: Use existing order.totals.shipping in edit mode - Create mode: Still calculates from shipping method Issue 2: Meta fields not appearing without data (DOCUMENTED) - Problem: Private meta fields dont appear if no data exists yet - Example: Admin cannot input tracking number on first time - Root cause: Fields only exposed if data exists in database - Solution: Plugins MUST register fields via MetaFieldsRegistry - Registration makes field available even when empty Updated METABOX_COMPAT.md: - Changed optional to REQUIRED for field registration - Added critical warning section - Explained private vs public meta behavior - Private meta: MUST register to appear - Public meta: Auto-exposed, no registration needed The Flow (Corrected): 1. Plugin registers field -> Field appears in UI (even empty) 2. Admin inputs data -> Saved to database 3. Data visible in both admins Without Registration: - Private meta (_field): Not exposed, not editable - Public meta (field): Auto-exposed, auto-editable Why Private Meta Requires Registration: - Security: Hidden by default - Privacy: Prevents exposing sensitive data - Control: Plugins explicitly declare visibility Files Changed: - OrderForm.tsx: Use existing shipping total in edit mode - METABOX_COMPAT.md: Critical documentation updates Result: - Shipping no longer recalculates on edit - Clear documentation on field registration requirement - Developers know they MUST register private meta fields
This commit is contained in:
@@ -604,7 +604,7 @@ update_post_meta($order_id, '_tracking_number', '1234567890');
|
|||||||
update_post_meta($order_id, '_tracking_provider', 'JNE');
|
update_post_meta($order_id, '_tracking_provider', 'JNE');
|
||||||
```
|
```
|
||||||
|
|
||||||
**Plugin registers fields for WooNooW (optional, for better UX):**
|
**Plugin registers fields for WooNooW (REQUIRED for UI display):**
|
||||||
```php
|
```php
|
||||||
// In plugin's main file or init hook
|
// In plugin's main file or init hook
|
||||||
add_action('woonoow/register_meta_fields', function() {
|
add_action('woonoow/register_meta_fields', function() {
|
||||||
@@ -649,7 +649,7 @@ update_field('custom_field', 'value', $product_id);
|
|||||||
// Stored as: update_post_meta($product_id, 'custom_field', 'value');
|
// Stored as: update_post_meta($product_id, 'custom_field', 'value');
|
||||||
```
|
```
|
||||||
|
|
||||||
**Register for WooNooW (optional):**
|
**Register for WooNooW (REQUIRED for UI display):**
|
||||||
```php
|
```php
|
||||||
add_action('woonoow/register_meta_fields', function() {
|
add_action('woonoow/register_meta_fields', function() {
|
||||||
\WooNooW\Compat\MetaFieldsRegistry::register_product_field('custom_field', [
|
\WooNooW\Compat\MetaFieldsRegistry::register_product_field('custom_field', [
|
||||||
@@ -666,7 +666,7 @@ add_action('woonoow/register_meta_fields', function() {
|
|||||||
- ✅ Synced with ACF
|
- ✅ Synced with ACF
|
||||||
- ✅ Works with both admins
|
- ✅ Works with both admins
|
||||||
|
|
||||||
### Example 3: Custom Plugin (No Registration)
|
### Example 3: Public Meta (Auto-Exposed, No Registration Needed)
|
||||||
|
|
||||||
**Plugin stores data:**
|
**Plugin stores data:**
|
||||||
```php
|
```php
|
||||||
@@ -793,10 +793,41 @@ MetaFieldsRegistry::register_order_field('_field_name', [
|
|||||||
|
|
||||||
**For Plugin Developers:**
|
**For Plugin Developers:**
|
||||||
1. ✅ Continue using standard WP/WooCommerce meta storage
|
1. ✅ Continue using standard WP/WooCommerce meta storage
|
||||||
2. ✅ Optionally register fields for better UX
|
2. ✅ **MUST register private meta fields** (starting with `_`) for UI display
|
||||||
3. ✅ No special integration needed
|
3. ✅ Public meta (no `_`) auto-exposed, no registration needed
|
||||||
4. ✅ Works with both classic and WooNooW admin
|
4. ✅ Works with both classic and WooNooW admin
|
||||||
|
|
||||||
|
**⚠️ CRITICAL: Private Meta Field Registration**
|
||||||
|
|
||||||
|
Private meta fields (starting with `_`) **MUST be registered** to appear in WooNooW UI:
|
||||||
|
|
||||||
|
**Why?**
|
||||||
|
- Security: Private meta is hidden by default
|
||||||
|
- Privacy: Prevents exposing sensitive data
|
||||||
|
- Control: Plugins explicitly declare what should be visible
|
||||||
|
|
||||||
|
**The Flow:**
|
||||||
|
1. Plugin registers field → Field appears in UI (even if empty)
|
||||||
|
2. Admin inputs data → Saved to database
|
||||||
|
3. Data visible in both admins
|
||||||
|
|
||||||
|
**Without Registration:**
|
||||||
|
- Private meta: ❌ Not exposed, not editable
|
||||||
|
- Public meta: ✅ Auto-exposed, auto-editable
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```php
|
||||||
|
// This field will NOT appear without registration
|
||||||
|
update_post_meta($order_id, '_tracking_number', '123');
|
||||||
|
|
||||||
|
// Register it to make it appear
|
||||||
|
add_action('woonoow/register_meta_fields', function() {
|
||||||
|
MetaFieldsRegistry::register_order_field('_tracking_number', [...]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Now admin can see and edit it, even when empty!
|
||||||
|
```
|
||||||
|
|
||||||
**For WooNooW Core:**
|
**For WooNooW Core:**
|
||||||
1. ✅ Zero addon dependencies
|
1. ✅ Zero addon dependencies
|
||||||
2. ✅ Provides mechanism, not integration
|
2. ✅ Provides mechanism, not integration
|
||||||
|
|||||||
@@ -314,11 +314,18 @@ export default function OrderForm({
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Calculate shipping cost
|
// Calculate shipping cost
|
||||||
|
// In edit mode: use existing order shipping total (fixed unless address changes)
|
||||||
|
// In create mode: calculate from selected shipping method
|
||||||
const shippingCost = React.useMemo(() => {
|
const shippingCost = React.useMemo(() => {
|
||||||
|
if (mode === 'edit' && initial?.totals?.shipping !== undefined) {
|
||||||
|
// Use existing shipping total from order
|
||||||
|
return Number(initial.totals.shipping) || 0;
|
||||||
|
}
|
||||||
|
// Create mode: calculate from shipping method
|
||||||
if (!shippingMethod) return 0;
|
if (!shippingMethod) return 0;
|
||||||
const method = shippings.find(s => s.id === shippingMethod);
|
const method = shippings.find(s => s.id === shippingMethod);
|
||||||
return method ? Number(method.cost) || 0 : 0;
|
return method ? Number(method.cost) || 0 : 0;
|
||||||
}, [shippingMethod, shippings]);
|
}, [mode, initial?.totals?.shipping, shippingMethod, shippings]);
|
||||||
|
|
||||||
// Calculate discount from validated coupons
|
// Calculate discount from validated coupons
|
||||||
const couponDiscount = React.useMemo(() => {
|
const couponDiscount = React.useMemo(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user