# WooNooW Addon Injection Guide **Version:** 1.0.0 **Last Updated:** 2025-10-28 **Status:** Production Ready --- ## 📋 Table of Contents 1. [Overview](#overview) 2. [Admin SPA Addons](#admin-spa-addons) - [Quick Start](#quick-start) - [Addon Registration](#addon-registration) - [Route Registration](#route-registration) - [Navigation Injection](#navigation-injection) - [Component Development](#component-development) - [Best Practices](#best-practices) 3. [Customer SPA Addons](#customer-spa-addons) *(Coming Soon)* 4. [Testing & Debugging](#testing--debugging) 5. [Examples](#examples) 6. [Troubleshooting](#troubleshooting) --- ## Overview WooNooW provides a **powerful addon injection system** that allows third-party plugins to seamlessly integrate with the React-powered admin SPA. Addons can: - ✅ Register custom SPA routes - ✅ Inject navigation menu items - ✅ Add submenu items to existing sections - ✅ Load React components dynamically - ✅ Declare dependencies and capabilities - ✅ Maintain full isolation and safety **No iframes, no hacks, just clean React integration!** --- ## Admin SPA Addons ### Quick Start **5-Minute Integration:** ```php 'my-addon', 'name' => 'My Addon', 'version' => '1.0.0', 'author' => 'Your Name', 'description' => 'My awesome addon', 'spa_bundle' => plugin_dir_url(__FILE__) . 'dist/addon.js', 'dependencies' => ['woocommerce' => '8.0'], ]; return $addons; }); // 2. Register your routes add_filter('woonoow/spa_routes', function($routes) { $routes[] = [ 'path' => '/my-addon', 'component_url' => plugin_dir_url(__FILE__) . 'dist/MyAddonPage.js', 'capability' => 'manage_woocommerce', 'title' => 'My Addon', ]; return $routes; }); // 3. Add navigation item add_filter('woonoow/nav_tree', function($tree) { $tree[] = [ 'key' => 'my-addon', 'label' => 'My Addon', 'path' => '/my-addon', 'icon' => 'puzzle', // lucide icon name 'children' => [], ]; return $tree; }); ``` **That's it!** Your addon is now integrated into WooNooW. --- ### Addon Registration **Filter:** `woonoow/addon_registry` **Priority:** 20 (runs on `plugins_loaded`) **File:** `includes/Compat/AddonRegistry.php` #### Configuration Schema ```php add_filter('woonoow/addon_registry', function($addons) { $addons['addon-id'] = [ // Required 'id' => 'addon-id', // Unique identifier 'name' => 'Addon Name', // Display name 'version' => '1.0.0', // Semantic version // Optional 'author' => 'Author Name', // Author name 'description' => 'Description', // Short description 'spa_bundle' => 'https://...', // Main JS bundle URL // Dependencies (optional) 'dependencies' => [ 'woocommerce' => '8.0', // Min WooCommerce version 'wordpress' => '6.0', // Min WordPress version ], // Advanced (optional) 'routes' => [], // Route definitions 'nav_items' => [], // Nav item definitions 'widgets' => [], // Widget definitions ]; return $addons; }); ``` #### Dependency Validation WooNooW automatically validates dependencies: ```php 'dependencies' => [ 'woocommerce' => '8.0', // Requires WooCommerce 8.0+ 'wordpress' => '6.4', // Requires WordPress 6.4+ ] ``` If dependencies are not met: - ❌ Addon is disabled automatically - ❌ Routes are not registered - ❌ Navigation items are hidden --- ### Route Registration **Filter:** `woonoow/spa_routes` **Priority:** 25 (runs on `plugins_loaded`) **File:** `includes/Compat/RouteRegistry.php` #### Basic Route ```php add_filter('woonoow/spa_routes', function($routes) { $routes[] = [ 'path' => '/subscriptions', 'component_url' => plugin_dir_url(__FILE__) . 'dist/SubscriptionsList.js', 'capability' => 'manage_woocommerce', 'title' => 'Subscriptions', ]; return $routes; }); ``` #### Multiple Routes ```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' => 'All Subscriptions', ]; $routes[] = [ 'path' => '/subscriptions/new', 'component_url' => $base_url . 'SubscriptionNew.js', 'capability' => 'manage_woocommerce', 'title' => 'New Subscription', ]; $routes[] = [ 'path' => '/subscriptions/:id', 'component_url' => $base_url . 'SubscriptionDetail.js', 'capability' => 'manage_woocommerce', 'title' => 'Subscription Detail', ]; return $routes; }); ``` #### Route Configuration | Property | Type | Required | Description | |----------|------|----------|-------------| | `path` | string | ✅ Yes | Route path (must start with `/`) | | `component_url` | string | ✅ Yes | URL to React component JS file | | `capability` | string | No | WordPress capability (default: `manage_woocommerce`) | | `title` | string | No | Page title | | `exact` | boolean | No | Exact path match (default: `false`) | | `props` | object | No | Props to pass to component | --- ### Navigation Injection #### Add Main Menu Item **Filter:** `woonoow/nav_tree` **Priority:** 30 (runs on `plugins_loaded`) **File:** `includes/Compat/NavigationRegistry.php` ```php add_filter('woonoow/nav_tree', function($tree) { $tree[] = [ 'key' => 'subscriptions', 'label' => __('Subscriptions', 'my-addon'), 'path' => '/subscriptions', 'icon' => 'repeat', // lucide-react icon name 'children' => [ [ 'label' => __('All Subscriptions', 'my-addon'), 'mode' => 'spa', 'path' => '/subscriptions', ], [ 'label' => __('New', 'my-addon'), 'mode' => 'spa', 'path' => '/subscriptions/new', ], ], ]; return $tree; }); ``` #### Inject into Existing Section **Filter:** `woonoow/nav_tree/{key}/children` ```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; }); ``` #### Available Sections | Key | Label | Path | |-----|-------|------| | `dashboard` | Dashboard | `/` | | `orders` | Orders | `/orders` | | `products` | Products | `/products` | | `coupons` | Coupons | `/coupons` | | `customers` | Customers | `/customers` | | `settings` | Settings | `/settings` | #### Navigation Item Schema ```typescript { key: string; // Unique key (for main items) label: string; // Display label (i18n recommended) path: string; // Route path icon?: string; // Lucide icon name (main items only) mode: 'spa' | 'bridge'; // Render mode href?: string; // External URL (bridge mode) exact?: boolean; // Exact path match children?: SubItem[]; // Submenu items } ``` #### Lucide Icons WooNooW uses [lucide-react](https://lucide.dev/) icons (16-20px, 1.5px stroke). **Popular icons:** - `layout-dashboard` - Dashboard - `receipt-text` - Orders - `package` - Products - `tag` - Coupons - `users` - Customers - `settings` - Settings - `repeat` - Subscriptions - `calendar` - Bookings - `credit-card` - Payments - `bar-chart` - Analytics --- ### Component Development #### Component Structure Your React component will be dynamically imported and rendered: ```typescript // dist/MyAddonPage.tsx import React from 'react'; export default function MyAddonPage(props: any) { return (

My Addon

Welcome to my addon!

); } ``` #### Access WooNooW APIs ```typescript // Access REST API const api = (window as any).WNW_API; const response = await fetch(`${api.root}my-addon/endpoint`, { headers: { 'X-WP-Nonce': api.nonce, }, }); // Access store data const store = (window as any).WNW_STORE; console.log('Currency:', store.currency); console.log('Symbol:', store.currency_symbol); // Access site info const wnw = (window as any).wnw; console.log('Site Title:', wnw.siteTitle); console.log('Admin URL:', wnw.adminUrl); ``` #### Use WooNooW Components ```typescript import { __ } from '@/lib/i18n'; import { formatMoney } from '@/lib/currency'; import { Button } from '@/components/ui/button'; import { Card } from '@/components/ui/card'; export default function MyAddonPage() { return (

{__('My Addon', 'my-addon')}

{formatMoney(1234.56)}

); } ``` #### Build Your Component **Using Vite:** ```javascript // vite.config.js import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], build: { lib: { entry: 'src/MyAddonPage.tsx', name: 'MyAddon', fileName: 'MyAddonPage', formats: ['es'], }, rollupOptions: { external: ['react', 'react-dom'], output: { globals: { react: 'React', 'react-dom': 'ReactDOM', }, }, }, }, }); ``` ```bash npm run build ``` --- ### Best Practices #### ✅ DO: 1. **Use Semantic Versioning** ```php 'version' => '1.2.3' ``` 2. **Declare Dependencies** ```php 'dependencies' => ['woocommerce' => '8.0'] ``` 3. **Check Capabilities** ```php 'capability' => 'manage_woocommerce' ``` 4. **Internationalize Strings** ```php 'label' => __('Subscriptions', 'my-addon') ``` 5. **Use Namespaced Hooks** ```php add_filter('woonoow/addon_registry', ...) ``` 6. **Validate User Input** ```php $value = sanitize_text_field($_POST['value']); ``` 7. **Handle Errors Gracefully** ```typescript try { // Load component } catch (error) { // Show error message } ``` 8. **Follow WooNooW UI Patterns** - Use Tailwind CSS classes - Use Shadcn UI components - Follow mobile-first design - Use `.ui-ctrl` class for controls #### ❌ DON'T: 1. **Don't Hardcode URLs** ```php // ❌ Bad 'component_url' => 'https://mysite.com/addon.js' // ✅ Good 'component_url' => plugin_dir_url(__FILE__) . 'dist/addon.js' ``` 2. **Don't Skip Capability Checks** ```php // ❌ Bad 'capability' => '' // ✅ Good 'capability' => 'manage_woocommerce' ``` 3. **Don't Use Generic Hook Names** ```php // ❌ Bad add_filter('addon_registry', ...) // ✅ Good add_filter('woonoow/addon_registry', ...) ``` 4. **Don't Modify Core Navigation** ```php // ❌ Bad - Don't remove core items unset($tree[0]); // ✅ Good - Add your own items $tree[] = ['key' => 'my-addon', ...]; ``` 5. **Don't Block the Main Thread** ```typescript // ❌ Bad while (loading) { /* wait */ } // ✅ Good if (loading) return ; ``` 6. **Don't Use Inline Styles** ```typescript // ❌ Bad
// ✅ Good
``` --- ## Customer SPA Addons **Status:** 🚧 Coming Soon Customer SPA addon injection will support: - Cart page customization - Checkout step injection - My Account page tabs - Widget areas - Custom forms **Stay tuned for updates!** --- ## Testing & Debugging ### Enable Debug Mode ```php // wp-config.php define('WNW_DEV', true); ``` This enables: - ✅ Console logging - ✅ Cache flushing - ✅ Detailed error messages ### Check Addon Registration ```javascript // Browser console console.log(window.WNW_ADDONS); console.log(window.WNW_ADDON_ROUTES); console.log(window.WNW_NAV_TREE); ``` ### Flush Caches ```php // Programmatically do_action('woonoow_flush_caches'); // Or via URL (admins only) // https://yoursite.com/wp-admin/?flush_wnw_cache=1 ``` ### Common Issues **Addon not appearing?** - Check dependencies are met - Verify capability requirements - Check browser console for errors - Flush caches **Route not loading?** - Verify `component_url` is correct - Check file exists and is accessible - Look for JS errors in console - Ensure component exports default **Navigation not showing?** - Check filter priority - Verify path matches route - Check i18n strings load - Inspect `window.WNW_NAV_TREE` --- ## Examples ### Example 1: Simple Addon ```php 'hello-world', 'name' => 'Hello World', 'version' => '1.0.0', ]; return $addons; }); add_filter('woonoow/spa_routes', function($routes) { $routes[] = [ 'path' => '/hello', 'component_url' => plugin_dir_url(__FILE__) . 'dist/Hello.js', 'capability' => 'read', // All logged-in users 'title' => 'Hello World', ]; return $routes; }); add_filter('woonoow/nav_tree', function($tree) { $tree[] = [ 'key' => 'hello', 'label' => 'Hello', 'path' => '/hello', 'icon' => 'smile', 'children' => [], ]; return $tree; }); ``` ```typescript // dist/Hello.tsx import React from 'react'; export default function Hello() { return (

Hello, WooNooW!

); } ``` ### Example 2: Full-Featured Addon See `ADDON_INJECTION_READINESS_REPORT.md` for the complete Subscriptions addon example. --- ## Troubleshooting ### Addon Registry Issues **Problem:** Addon not registered **Solutions:** 1. Check `plugins_loaded` hook fires 2. Verify filter name: `woonoow/addon_registry` 3. Check dependencies are met 4. Look for PHP errors in debug log ### Route Issues **Problem:** Route returns 404 **Solutions:** 1. Verify path starts with `/` 2. Check `component_url` is accessible 3. Ensure route is registered before navigation 4. Check capability requirements ### Navigation Issues **Problem:** Menu item not showing **Solutions:** 1. Check filter: `woonoow/nav_tree` or `woonoow/nav_tree/{key}/children` 2. Verify path matches registered route 3. Check i18n strings are loaded 4. Inspect `window.WNW_NAV_TREE` in console ### Component Loading Issues **Problem:** Component fails to load **Solutions:** 1. Check component exports `default` 2. Verify file is built correctly 3. Check for JS errors in console 4. Ensure React/ReactDOM are available 5. Test component URL directly in browser --- ## Support & Resources **Documentation:** - `ADDON_INJECTION_READINESS_REPORT.md` - Technical analysis - `ADDONS_ADMIN_UI_REQUIREMENTS.md` - Requirements & status - `PROGRESS_NOTE.md` - Development progress **Code References:** - `includes/Compat/AddonRegistry.php` - Addon registration - `includes/Compat/RouteRegistry.php` - Route management - `includes/Compat/NavigationRegistry.php` - Navigation building - `admin-spa/src/App.tsx` - Dynamic route loading - `admin-spa/src/nav/tree.ts` - Navigation tree **Community:** - GitHub Issues: Report bugs - Discussions: Ask questions - Examples: Share your addons --- **End of Guide** **Version:** 1.0.0 **Last Updated:** 2025-10-28 **Status:** ✅ Production Ready