# WooNooW Addon Hook System ## Problem Statement **Question:** How can WooNooW SPA support addons without hardcoding specific components? **Example of WRONG approach:** ```typescript // ❌ This is hardcoding - breaks if addon doesn't exist import { SubdistrictSelector } from 'woonoow-indonesia-shipping'; {/* ❌ Error if plugin not installed */} ``` **This is "supporting specific 3rd party addons" - exactly what we want to AVOID!** --- ## **The Solution: WordPress-Style Hook System in React** ### **Architecture Overview** ``` WooNooW Core (Base): - Provides hook points - Renders whatever addons register - No knowledge of specific addons Addon Plugins: - Register components via hooks - Only loaded if plugin is active - Self-contained functionality ``` --- ## **Implementation** ### **Step 1: Create Hook System in WooNooW Core** ```typescript // admin-spa/src/lib/hooks.ts type HookCallback = (...args: any[]) => any; class HookSystem { private filters: Map = new Map(); private actions: Map = new Map(); /** * Add a filter hook * Similar to WordPress add_filter() */ addFilter(hookName: string, callback: HookCallback, priority: number = 10) { if (!this.filters.has(hookName)) { this.filters.set(hookName, []); } const hooks = this.filters.get(hookName)!; hooks.push({ callback, priority }); hooks.sort((a, b) => a.priority - b.priority); } /** * Apply filters * Similar to WordPress apply_filters() */ applyFilters(hookName: string, value: any, ...args: any[]): any { const hooks = this.filters.get(hookName) || []; return hooks.reduce((currentValue, { callback }) => { return callback(currentValue, ...args); }, value); } /** * Add an action hook * Similar to WordPress add_action() */ addAction(hookName: string, callback: HookCallback, priority: number = 10) { if (!this.actions.has(hookName)) { this.actions.set(hookName, []); } const hooks = this.actions.get(hookName)!; hooks.push({ callback, priority }); hooks.sort((a, b) => a.priority - b.priority); } /** * Do action * Similar to WordPress do_action() */ doAction(hookName: string, ...args: any[]) { const hooks = this.actions.get(hookName) || []; hooks.forEach(({ callback }) => callback(...args)); } } // Export singleton instance export const hooks = new HookSystem(); // Export helper functions export const addFilter = hooks.addFilter.bind(hooks); export const applyFilters = hooks.applyFilters.bind(hooks); export const addAction = hooks.addAction.bind(hooks); export const doAction = hooks.doAction.bind(hooks); ``` ### **Step 2: Add Hook Points in OrderForm.tsx** ```typescript // admin-spa/src/routes/Orders/OrderForm.tsx import { applyFilters, doAction } from '@/lib/hooks'; export function OrderForm() { const [formData, setFormData] = useState(initialData); // Hook: Allow addons to modify form data const processedFormData = applyFilters('woonoow_order_form_data', formData); // Hook: Allow addons to add validation const validateForm = () => { let errors = {}; // Core validation if (!formData.customer_id) { errors.customer_id = 'Customer is required'; } // Hook: Let addons add their validation errors = applyFilters('woonoow_order_form_validation', errors, formData); return errors; }; return (
{/* Customer Section */} {/* Billing Address */} {/* Hook: Allow addons to inject fields after billing */} {applyFilters('woonoow_order_form_after_billing', null, formData, setFormData)} {/* Shipping Address */} {/* Hook: Allow addons to inject fields after shipping */} {applyFilters('woonoow_order_form_after_shipping', null, formData, setFormData)} {/* Shipping Method Selection */} {/* Core shipping method selector */}