# WooNooW Hooks & Filters Registry **Version:** 1.0.0 **Last Updated:** 2025-10-28 **Status:** Production Ready --- ## 📋 Table of Contents 1. [Hook Naming Convention](#hook-naming-convention) 2. [Addon System Hooks](#addon-system-hooks) 3. [Navigation Hooks](#navigation-hooks) 4. [Route Hooks](#route-hooks) 5. [Content Injection Hooks](#content-injection-hooks) 6. [Asset Hooks](#asset-hooks) 7. [Future Hooks](#future-hooks) 8. [Hook Tree Structure](#hook-tree-structure) --- ## Hook Naming Convention All WooNooW hooks follow this structure: ``` woonoow/{category}/{action}[/{subcategory}] ``` **Rules:** 1. Always prefix with `woonoow/` 2. Use lowercase with underscores 3. Use singular nouns for registries (`addon_registry`, not `addons_registry`) 4. Use hierarchical structure for nested items (`nav_tree/products/children`) 5. Use descriptive names that indicate purpose --- ## Addon System Hooks ### `woonoow/addon_registry` **Type:** Filter **Priority:** 20 (runs on `plugins_loaded`) **File:** `includes/Compat/AddonRegistry.php` **Purpose:** Register addon metadata with WooNooW **Parameters:** - `$addons` (array) - Array of addon configurations **Returns:** array **Example:** ```php add_filter('woonoow/addon_registry', function($addons) { $addons['my-addon'] = [ 'id' => 'my-addon', 'name' => 'My Addon', 'version' => '1.0.0', 'author' => 'Author Name', 'description' => 'Addon description', 'spa_bundle' => plugin_dir_url(__FILE__) . 'dist/addon.js', 'dependencies' => ['woocommerce' => '8.0'], ]; return $addons; }); ``` **Schema:** ```typescript { id: string; // Required: Unique identifier name: string; // Required: Display name version: string; // Required: Semantic version author?: string; // Optional: Author name description?: string; // Optional: Short description spa_bundle?: string; // Optional: Main JS bundle URL dependencies?: { // Optional: Plugin dependencies [plugin: string]: string; // plugin => min version }; } ``` --- ## Navigation Hooks ### `woonoow/nav_tree` **Type:** Filter **Priority:** 30 (runs on `plugins_loaded`) **File:** `includes/Compat/NavigationRegistry.php` **Purpose:** Modify the entire navigation tree **Parameters:** - `$tree` (array) - Array of main navigation nodes **Returns:** array **Example:** ```php add_filter('woonoow/nav_tree', function($tree) { $tree[] = [ 'key' => 'subscriptions', 'label' => __('Subscriptions', 'my-addon'), 'path' => '/subscriptions', 'icon' => 'repeat', // lucide icon name 'children' => [ [ 'label' => __('All Subscriptions', 'my-addon'), 'mode' => 'spa', 'path' => '/subscriptions', ], [ 'label' => __('New', 'my-addon'), 'mode' => 'spa', 'path' => '/subscriptions/new', ], ], ]; return $tree; }); ``` **Schema:** ```typescript { key: string; // Required: Unique key label: string; // Required: Display label (i18n) path: string; // Required: Route path icon?: string; // Optional: Lucide icon name children?: SubItem[]; // Optional: Submenu items } ``` --- ### `woonoow/nav_tree/{key}/children` **Type:** Filter **Priority:** 30 (runs on `plugins_loaded`) **File:** `includes/Compat/NavigationRegistry.php` **Purpose:** Inject items into specific section's submenu **Available Keys:** - `dashboard` - Dashboard section - `orders` - Orders section (no children by design) - `products` - Products section - `coupons` - Coupons section - `customers` - Customers section - `settings` - Settings section - *Any custom section key added by addons* **Parameters:** - `$children` (array) - Array of submenu items **Returns:** array **Example:** ```php // Add "Bundles" to Products menu add_filter('woonoow/nav_tree/products/children', function($children) { $children[] = [ 'label' => __('Bundles', 'my-addon'), 'mode' => 'spa', 'path' => '/products/bundles', ]; return $children; }); // Add "Reports" to Dashboard menu add_filter('woonoow/nav_tree/dashboard/children', function($children) { $children[] = [ 'label' => __('Custom Reports', 'my-addon'), 'mode' => 'spa', 'path' => '/reports', ]; return $children; }); ``` **Schema:** ```typescript { label: string; // Required: Display label (i18n) mode: 'spa' | 'bridge'; // Required: Render mode path?: string; // Required for SPA mode href?: string; // Required for bridge mode exact?: boolean; // Optional: Exact path match } ``` --- ## Route Hooks ### `woonoow/spa_routes` **Type:** Filter **Priority:** 25 (runs on `plugins_loaded`) **File:** `includes/Compat/RouteRegistry.php` **Purpose:** Register SPA routes for addon pages **Parameters:** - `$routes` (array) - Array of route configurations **Returns:** array **Example:** ```php add_filter('woonoow/spa_routes', function($routes) { $base_url = plugin_dir_url(__FILE__) . 'dist/'; $routes[] = [ 'path' => '/subscriptions', 'component_url' => $base_url . 'SubscriptionsList.js', 'capability' => 'manage_woocommerce', 'title' => __('Subscriptions', 'my-addon'), ]; $routes[] = [ 'path' => '/subscriptions/:id', 'component_url' => $base_url . 'SubscriptionDetail.js', 'capability' => 'manage_woocommerce', 'title' => __('Subscription Detail', 'my-addon'), ]; return $routes; }); ``` **Schema:** ```typescript { path: string; // Required: Route path (must start with /) component_url: string; // Required: URL to React component JS capability?: string; // Optional: WordPress capability (default: manage_woocommerce) title?: string; // Optional: Page title exact?: boolean; // Optional: Exact path match (default: false) props?: object; // Optional: Props to pass to component } ``` --- ## Content Injection Hooks ### `woonoow/dashboard/widgets` (Future) **Type:** Filter **Priority:** TBD **File:** `includes/Compat/WidgetRegistry.php` (planned) **Purpose:** Add widgets to dashboard **Status:** 📋 Planned **Example:** ```php add_filter('woonoow/dashboard/widgets', function($widgets) { $widgets[] = [ 'id' => 'subscription-stats', 'title' => __('Active Subscriptions', 'my-addon'), 'component_url' => plugin_dir_url(__FILE__) . 'dist/SubscriptionWidget.js', 'position' => 'top-right', 'size' => 'medium', ]; return $widgets; }); ``` --- ### `woonoow/order/detail/panels` (Future) **Type:** Filter **Priority:** TBD **File:** `includes/Compat/WidgetRegistry.php` (planned) **Purpose:** Add panels to order detail page **Status:** 📋 Planned **Example:** ```php add_filter('woonoow/order/detail/panels', function($panels, $order_id) { if (wcs_order_contains_subscription($order_id)) { $panels[] = [ 'id' => 'subscription-info', 'title' => __('Subscription', 'my-addon'), 'content' => render_subscription_panel($order_id), ]; } return $panels; }, 10, 2); ``` --- ### `woonoow/orders/toolbar_actions` (Future) **Type:** Filter **Priority:** TBD **File:** TBD **Purpose:** Add actions to orders list toolbar **Status:** 📋 Planned **Example:** ```php add_filter('woonoow/orders/toolbar_actions', function($actions) { $actions[] = [ 'label' => __('Export to CSV', 'my-addon'), 'callback' => 'my_addon_export_orders', 'icon' => 'download', ]; return $actions; }); ``` --- ## Payment & Shipping Hooks ### `woonoow/payment_gateway_channels` **Type:** Filter **Priority:** 10-30 **File:** `includes/Api/OrdersController.php`, `includes/Compat/PaymentChannels.php` **Purpose:** Detect and expose payment gateway channels (e.g., bank accounts) **Parameters:** - `$channels` (array) - Array of channel configurations - `$gateway_id` (string) - Gateway ID - `$gateway` (object) - Gateway instance **Returns:** array **Example:** ```php add_filter('woonoow/payment_gateway_channels', function($channels, $gateway_id, $gateway) { if ($gateway_id === 'stripe') { $accounts = get_option('stripe_connected_accounts', []); foreach ($accounts as $account) { $channels[] = [ 'id' => 'stripe_' . $account['id'], 'title' => $account['name'], 'meta' => $account, ]; } } return $channels; }, 30, 3); ``` **Built-in Handlers:** - **BACS Detection** (Priority 10) - Automatically detects bank transfer accounts - **Custom Channels** (Priority 20) - Placeholder for third-party integrations **Schema:** ```typescript { id: string; // Required: Unique channel ID title: string; // Required: Display name meta?: any; // Optional: Additional channel data } ``` **Use Case:** When a payment gateway has multiple accounts or channels (e.g., multiple bank accounts for BACS), this filter allows them to be exposed as separate options in the order form. --- ## Asset Hooks ### `woonoow/admin_is_dev` **Type:** Filter **Priority:** N/A **File:** `includes/Admin/Assets.php` **Purpose:** Force dev/prod mode for admin assets **Parameters:** - `$is_dev` (bool) - Whether dev mode is enabled **Returns:** bool **Example:** ```php // Force dev mode add_filter('woonoow/admin_is_dev', '__return_true'); // Force prod mode add_filter('woonoow/admin_is_dev', '__return_false'); ``` --- ### `woonoow/admin_dev_server` **Type:** Filter **Priority:** N/A **File:** `includes/Admin/Assets.php` **Purpose:** Change dev server URL **Parameters:** - `$url` (string) - Dev server URL **Returns:** string **Example:** ```php add_filter('woonoow/admin_dev_server', function($url) { return 'http://localhost:3000'; }); ``` --- ## Future Hooks ### Planned for Future Releases #### Product Module - `woonoow/product/types` - Register custom product types - `woonoow/product/fields` - Add custom product fields - `woonoow/product/detail/tabs` - Add tabs to product detail #### Customer Module - `woonoow/customer/fields` - Add custom customer fields - `woonoow/customer/detail/panels` - Add panels to customer detail #### Settings Module - `woonoow/settings/tabs` - Add custom settings tabs - `woonoow/settings/sections` - Add settings sections #### Email Module - `woonoow/email/templates` - Register custom email templates - `woonoow/email/variables` - Add email template variables #### Reports Module - `woonoow/reports/types` - Register custom report types - `woonoow/reports/widgets` - Add report widgets --- ## Hook Tree Structure ``` woonoow/ ├── addon_registry ✅ ACTIVE (Priority: 20) │ └── Purpose: Register addon metadata │ ├── spa_routes ✅ ACTIVE (Priority: 25) │ └── Purpose: Register SPA routes │ ├── nav_tree ✅ ACTIVE (Priority: 30) │ ├── Purpose: Modify navigation tree │ └── {section_key}/ │ └── children ✅ ACTIVE (Priority: 30) │ └── Purpose: Inject submenu items │ ├── payment_gateway_channels ✅ ACTIVE (Priority: 10-30) │ └── Purpose: Detect payment gateway channels │ ├── dashboard/ │ └── widgets 📋 PLANNED │ └── Purpose: Add dashboard widgets │ ├── order/ │ └── detail/ │ └── panels 📋 PLANNED │ └── Purpose: Add order detail panels │ ├── orders/ │ └── toolbar_actions 📋 PLANNED │ └── Purpose: Add toolbar actions │ ├── product/ │ ├── types 📋 PLANNED │ ├── fields 📋 PLANNED │ └── detail/ │ └── tabs 📋 PLANNED │ ├── customer/ │ ├── fields 📋 PLANNED │ └── detail/ │ └── panels 📋 PLANNED │ ├── settings/ │ ├── tabs 📋 PLANNED │ └── sections 📋 PLANNED │ ├── email/ │ ├── templates 📋 PLANNED │ └── variables 📋 PLANNED │ ├── reports/ │ ├── types 📋 PLANNED │ └── widgets 📋 PLANNED │ └── admin_is_dev ✅ ACTIVE └── Purpose: Force dev/prod mode ``` --- ## Hook Priority Guidelines **Standard Priorities:** - **10** - Early hooks (before WooNooW) - **20** - AddonRegistry (collect addon metadata) - **25** - RouteRegistry (collect routes) - **30** - NavigationRegistry (build nav tree) - **40** - Late hooks (after WooNooW) - **50+** - Very late hooks **Why This Order:** 1. AddonRegistry runs first to validate dependencies 2. RouteRegistry runs next to register routes 3. NavigationRegistry runs last to build complete tree **Custom Hook Priorities:** - Use **15** to run before AddonRegistry - Use **22** to run between Addon and Route - Use **27** to run between Route and Navigation - Use **35** to run after all registries --- ## Hook Usage Examples ### Complete Addon Integration ```php 'complete-addon', 'name' => 'Complete Addon', 'version' => '1.0.0', 'dependencies' => ['woocommerce' => '8.0'], ]; return $addons; }); // 2. Register routes (Priority: 25) add_filter('woonoow/spa_routes', function($routes) { $routes[] = [ 'path' => '/complete', 'component_url' => plugin_dir_url(__FILE__) . 'dist/Complete.js', 'capability' => 'manage_woocommerce', ]; return $routes; }); // 3. Add main menu (Priority: 30) add_filter('woonoow/nav_tree', function($tree) { $tree[] = [ 'key' => 'complete', 'label' => 'Complete', 'path' => '/complete', 'icon' => 'puzzle', 'children' => [], ]; return $tree; }); // 4. Inject into existing menu (Priority: 30) add_filter('woonoow/nav_tree/products/children', function($children) { $children[] = [ 'label' => 'Custom Products', 'mode' => 'spa', 'path' => '/complete/products', ]; return $children; }); ``` --- ## Best Practices ### ✅ DO: 1. **Use Correct Priority** ```php add_filter('woonoow/addon_registry', $callback, 20); ``` 2. **Return Modified Data** ```php add_filter('woonoow/nav_tree', function($tree) { $tree[] = ['key' => 'my-item', ...]; return $tree; // ✅ Always return }); ``` 3. **Validate Data** ```php add_filter('woonoow/spa_routes', function($routes) { if (!empty($my_route['path'])) { $routes[] = $my_route; } return $routes; }); ``` 4. **Use i18n** ```php 'label' => __('My Label', 'my-addon') ``` 5. **Check Dependencies** ```php if (class_exists('WooCommerce')) { add_filter('woonoow/addon_registry', ...); } ``` ### ❌ DON'T: 1. **Don't Forget to Return** ```php // ❌ Bad add_filter('woonoow/nav_tree', function($tree) { $tree[] = ['key' => 'my-item', ...]; // Missing return! }); ``` 2. **Don't Use Wrong Hook Name** ```php // ❌ Bad add_filter('woonoow_addon_registry', ...); // Wrong separator add_filter('addon_registry', ...); // Missing prefix ``` 3. **Don't Modify Core Items** ```php // ❌ Bad add_filter('woonoow/nav_tree', function($tree) { unset($tree[0]); // Don't remove core items return $tree; }); ``` 4. **Don't Use Generic Keys** ```php // ❌ Bad 'key' => 'item' // Too generic // ✅ Good 'key' => 'my-addon-subscriptions' ``` --- ## Testing Hooks ### Check Hook Registration ```javascript // Browser console console.log('Addons:', window.WNW_ADDONS); console.log('Routes:', window.WNW_ADDON_ROUTES); console.log('Nav Tree:', window.WNW_NAV_TREE); ``` ### Debug Hook Execution ```php // Add debug logging add_filter('woonoow/addon_registry', function($addons) { error_log('WooNooW: Addon registry filter fired'); error_log('WooNooW: Current addons: ' . print_r($addons, true)); $addons['my-addon'] = [...]; error_log('WooNooW: After adding my addon: ' . print_r($addons, true)); return $addons; }); ``` ### Flush Caches ```php // Flush all WooNooW caches do_action('woonoow_flush_caches'); // Or manually delete_option('wnw_addon_registry'); delete_option('wnw_spa_routes'); delete_option('wnw_nav_tree'); ``` --- ## Support & Resources **Documentation:** - `ADDON_INJECTION_GUIDE.md` - Complete developer guide - `PROJECT_SOP.md` - Development standards - `ADDONS_ADMIN_UI_REQUIREMENTS.md` - Requirements & status **Code References:** - `includes/Compat/AddonRegistry.php` - Addon registration - `includes/Compat/RouteRegistry.php` - Route management - `includes/Compat/NavigationRegistry.php` - Navigation building --- **End of Registry** **Version:** 1.0.0 **Last Updated:** 2025-10-28 **Status:** ✅ Production Ready