From cb91d0841c35d30357840df3472359201d9afb8f Mon Sep 17 00:00:00 2001 From: dwindown Date: Thu, 20 Nov 2025 12:17:35 +0700 Subject: [PATCH] plan: Complete implementation plan for Level 1 meta compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Implementation Plan Created: IMPLEMENTATION_PLAN_META_COMPAT.md** Following all documentation guidelines: - ADDON_BRIDGE_PATTERN.md (3-level strategy) - ADDON_DEVELOPMENT_GUIDE.md (hook system) - ADDON_REACT_INTEGRATION.md (React exposure) - METABOX_COMPAT.md (compatibility requirements) **Key Principles:** 1. ✅ Zero addon dependencies in core 2. ✅ Listen to WP/WooCommerce hooks (NOT WooNooW-specific) 3. ✅ Community does NOTHING extra 4. ❌ Do NOT support specific plugins 5. ❌ Do NOT integrate plugins into core **3 Phases:** Phase 1: Backend API Enhancement (2-3 days) - Add get_order_meta_data() / get_product_meta_data() - Add update_order_meta_data() / update_product_meta_data() - Expose meta in API responses - Add filters: woonoow/order_allowed_private_meta - Add filters: woonoow/order_updatable_meta - Add filters: woonoow/order_api_data - Add actions: woonoow/order_updated Phase 2: Frontend Components (3-4 days) - Create MetaFields.tsx component (generic field renderer) - Create useMetaFields.ts hook (registry access) - Update Orders/Edit.tsx to include meta fields - Update Products/Edit.tsx to include meta fields - Support all field types: text, textarea, number, select, checkbox Phase 3: PHP Registry System (2-3 days) - Create MetaFieldsRegistry.php - Add action: woonoow/register_meta_fields - Auto-register fields to allowed meta lists - Localize to JavaScript (window.WooNooWMetaFields) - Initialize in Plugin.php **Testing Plan:** - WooCommerce Shipment Tracking plugin - Advanced Custom Fields (ACF) - Custom metabox plugins - Meta data save/update - Field registration **Timeline:** 8-12 days (1.5-2 weeks) **Success Criteria:** ✅ Plugins using standard WP/WooCommerce meta work automatically ✅ No special integration needed ✅ Meta fields visible and editable ✅ Zero coupling with specific plugins ✅ Community does NOTHING extra Ready to start implementation! --- IMPLEMENTATION_PLAN_META_COMPAT.md | 640 +++++++++++++++++++++++++++++ 1 file changed, 640 insertions(+) create mode 100644 IMPLEMENTATION_PLAN_META_COMPAT.md diff --git a/IMPLEMENTATION_PLAN_META_COMPAT.md b/IMPLEMENTATION_PLAN_META_COMPAT.md new file mode 100644 index 0000000..8ade2ac --- /dev/null +++ b/IMPLEMENTATION_PLAN_META_COMPAT.md @@ -0,0 +1,640 @@ +# Implementation Plan: Level 1 Meta Compatibility + +## Objective +Make WooNooW listen to ALL standard WordPress/WooCommerce hooks for custom meta fields automatically. + +## Principles (From Documentation Review) + +### From ADDON_BRIDGE_PATTERN.md: +1. ✅ WooNooW Core = Zero addon dependencies +2. ✅ We listen to WP/WooCommerce hooks (NOT WooNooW-specific) +3. ✅ Community does NOTHING extra +4. ❌ We do NOT support specific plugins +5. ❌ We do NOT integrate plugins into core + +### From ADDON_DEVELOPMENT_GUIDE.md: +1. ✅ Hook system for functional extensions +2. ✅ Zero coupling with core +3. ✅ WordPress-style filters and actions + +### From ADDON_REACT_INTEGRATION.md: +1. ✅ Expose React runtime on window +2. ✅ Support vanilla JS/jQuery addons +3. ✅ No build process required for simple addons + +--- + +## Implementation Strategy + +### Phase 1: Backend API Enhancement (2-3 days) + +#### 1.1 OrdersController - Expose Meta Data + +**File:** `includes/Api/OrdersController.php` + +**Changes:** +```php +public static function show(WP_REST_Request $req) { + $order = wc_get_order($id); + + // ... existing data ... + + // Expose meta data (Level 1 compatibility) + $meta_data = self::get_order_meta_data($order); + $data['meta'] = $meta_data; + + // Allow plugins to modify response + $data = apply_filters('woonoow/order_api_data', $data, $order, $req); + + return new WP_REST_Response($data, 200); +} + +/** + * Get order meta data for API exposure + * Filters out internal meta unless explicitly allowed + */ +private static function get_order_meta_data($order) { + $meta_data = []; + + foreach ($order->get_meta_data() as $meta) { + $key = $meta->key; + $value = $meta->value; + + // Skip internal WooCommerce meta (starts with _wc_) + if (strpos($key, '_wc_') === 0) { + continue; + } + + // Public meta (no underscore) - always expose + if (strpos($key, '_') !== 0) { + $meta_data[$key] = $value; + continue; + } + + // Private meta (starts with _) - check if allowed + $allowed_private = apply_filters('woonoow/order_allowed_private_meta', [ + // Common shipping tracking fields + '_tracking_number', + '_tracking_provider', + '_tracking_url', + '_shipment_tracking_items', + '_wc_shipment_tracking_items', + + // Allow plugins to add their meta + ], $order); + + if (in_array($key, $allowed_private, true)) { + $meta_data[$key] = $value; + } + } + + return $meta_data; +} +``` + +**Update Method:** +```php +public static function update(WP_REST_Request $req) { + $order = wc_get_order($id); + $data = $req->get_json_params(); + + // ... existing update logic ... + + // Update custom meta fields (Level 1 compatibility) + if (isset($data['meta']) && is_array($data['meta'])) { + self::update_order_meta_data($order, $data['meta']); + } + + $order->save(); + + // Allow plugins to perform additional updates + do_action('woonoow/order_updated', $order, $data, $req); + + return new WP_REST_Response(['success' => true], 200); +} + +/** + * Update order meta data from API + */ +private static function update_order_meta_data($order, $meta_updates) { + // Get allowed updatable meta keys + $allowed = apply_filters('woonoow/order_updatable_meta', [ + '_tracking_number', + '_tracking_provider', + '_tracking_url', + // Allow plugins to add their meta + ], $order); + + foreach ($meta_updates as $key => $value) { + // Public meta (no underscore) - always allow + if (strpos($key, '_') !== 0) { + $order->update_meta_data($key, $value); + continue; + } + + // Private meta - check if allowed + if (in_array($key, $allowed, true)) { + $order->update_meta_data($key, $value); + } + } +} +``` + +#### 1.2 ProductsController - Expose Meta Data + +**File:** `includes/Api/ProductsController.php` + +**Changes:** (Same pattern as OrdersController) +```php +public static function get_product(WP_REST_Request $request) { + $product = wc_get_product($id); + + // ... existing data ... + + // Expose meta data (Level 1 compatibility) + $meta_data = self::get_product_meta_data($product); + $data['meta'] = $meta_data; + + // Allow plugins to modify response + $data = apply_filters('woonoow/product_api_data', $data, $product, $request); + + return new WP_REST_Response($data, 200); +} + +private static function get_product_meta_data($product) { + // Same logic as orders +} + +public static function update_product(WP_REST_Request $request) { + // ... existing logic ... + + if (isset($data['meta']) && is_array($data['meta'])) { + self::update_product_meta_data($product, $data['meta']); + } + + do_action('woonoow/product_updated', $product, $data, $request); +} +``` + +--- + +### Phase 2: Frontend Components (3-4 days) + +#### 2.1 MetaFields Component + +**File:** `admin-spa/src/components/MetaFields.tsx` + +**Purpose:** Generic component to display/edit meta fields + +```tsx +interface MetaField { + key: string; + label: string; + type: 'text' | 'textarea' | 'number' | 'select' | 'date' | 'checkbox'; + options?: Array<{value: string; label: string}>; + section?: string; + description?: string; + placeholder?: string; +} + +interface MetaFieldsProps { + meta: Record; + fields: MetaField[]; + onChange: (key: string, value: any) => void; + readOnly?: boolean; +} + +export function MetaFields({ meta, fields, onChange, readOnly }: MetaFieldsProps) { + if (fields.length === 0) return null; + + // Group fields by section + const sections = fields.reduce((acc, field) => { + const section = field.section || 'Additional Fields'; + if (!acc[section]) acc[section] = []; + acc[section].push(field); + return acc; + }, {} as Record); + + return ( +
+ {Object.entries(sections).map(([section, sectionFields]) => ( + + + {section} + + + {sectionFields.map(field => ( +
+ + + {field.type === 'text' && ( + onChange(field.key, e.target.value)} + disabled={readOnly} + placeholder={field.placeholder} + /> + )} + + {field.type === 'textarea' && ( +