9.6 KiB
Settings Submenu Fix - Complete Summary
🐛 Problem Identified
Issue: Settings submenu only appeared in standalone mode, not in wp-admin or fullscreen mode.
Root Cause: The navigation tree has TWO sources:
- Backend (PHP):
NavigationRegistry::get_base_tree()- Used in wp-admin and all modes - Frontend (TypeScript):
tree.tsfallback - Only used if backend fails
The backend was providing empty children for settings:
// NavigationRegistry.php line 159
'children' => [], // Settings children will be added by SettingsProvider
But SettingsProvider never actually populated the navigation tree!
✅ Solution Implemented
1. Fixed Backend Navigation Registry
File: includes/Compat/NavigationRegistry.php
Changes:
- Added
get_settings_children()method - Populated settings submenu in
get_base_tree() - Made backend the single source of truth
Code:
[
'key' => 'settings',
'label' => __('Settings', 'woonoow'),
'path' => '/settings',
'icon' => 'settings',
'children' => self::get_settings_children(), // ✅ Now populated!
],
Settings Children:
private static function get_settings_children(): array {
$admin = admin_url('admin.php');
return [
// WooNooW Settings
['label' => __('WooNooW', 'woonoow'), 'mode' => 'spa', 'path' => '/settings'],
// WooCommerce Settings (Most Used First)
['label' => __('General', 'woonoow'), 'mode' => 'spa', 'path' => '/settings/general'],
['label' => __('Payments', 'woonoow'), 'mode' => 'spa', 'path' => '/settings/payments'],
['label' => __('Shipping', 'woonoow'), 'mode' => 'spa', 'path' => '/settings/shipping'],
['label' => __('Products', 'woonoow'), 'mode' => 'spa', 'path' => '/settings/products'],
['label' => __('Tax', 'woonoow'), 'mode' => 'spa', 'path' => '/settings/tax'],
['label' => __('Accounts & Privacy', 'woonoow'), 'mode' => 'spa', 'path' => '/settings/accounts'],
['label' => __('Emails', 'woonoow'), 'mode' => 'spa', 'path' => '/settings/emails'],
// Less Common (Bridge to WP Admin for now)
['label' => __('Advanced', 'woonoow'), 'mode' => 'bridge', 'href' => $admin . '?page=wc-settings&tab=advanced'],
['label' => __('Integration', 'woonoow'), 'mode' => 'bridge', 'href' => $admin . '?page=wc-settings&tab=integration'],
['label' => __('Status', 'woonoow'), 'mode' => 'bridge', 'href' => $admin . '?page=wc-status'],
['label' => __('Extensions', 'woonoow'), 'mode' => 'bridge', 'href' => $admin . '?page=wc-addons'],
];
}
2. Frontend Already Correct
File: admin-spa/src/nav/tree.ts
The frontend fallback tree was already correct (we fixed it earlier), but it wasn't being used because the backend tree takes precedence.
Data Flow:
function getNavTreeFromBackend(): MainNode[] {
const backendTree = (window as any).WNW_NAV_TREE;
if (Array.isArray(backendTree) && backendTree.length > 0) {
return backendTree; // ✅ Backend tree used (from PHP)
}
// Fallback to static tree (for development/safety)
return getStaticFallbackTree();
}
🎯 Single Source of Truth Established
Backend (PHP) - PRIMARY SOURCE ✅
File: includes/Compat/NavigationRegistry.php
- Builds navigation tree on
inithook - Stores in
wnw_nav_treeoption - Localizes to
window.WNW_NAV_TREE - Used by all modes (wp-admin, fullscreen, standalone)
Frontend (TypeScript) - FALLBACK ONLY
File: admin-spa/src/nav/tree.ts
- Reads from
window.WNW_NAV_TREE(backend) - Falls back to static tree if backend unavailable
- Static tree matches backend structure
Flow Diagram
┌─────────────────────────────────────────┐
│ NavigationRegistry::build_nav_tree() │
│ (PHP - runs on init hook) │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Store in option: wnw_nav_tree │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Localize to: window.WNW_NAV_TREE │
│ (via Assets.php) │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Frontend reads: window.WNW_NAV_TREE │
│ (tree.ts) │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ useActiveSection() hook │
│ Returns: { main, children } │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ SubmenuBar component │
│ Renders: main.children │
└─────────────────────────────────────────┘
🧪 How to Test
1. Clear Navigation Cache
The navigation tree is cached in WordPress options. To rebuild:
- Deactivate and reactivate WooNooW plugin, OR
- Visit any admin page (tree rebuilds on
inithook)
2. Test in wp-admin Mode
- Go to
/wp-admin/admin.php?page=woonoow - Click "Settings" in sidebar
- Should see submenu: WooNooW, General, Payments, Shipping, Products, Tax, Accounts & Privacy, Emails, Advanced, Integration, Status, Extensions
3. Test in Fullscreen Mode
- Click fullscreen toggle
- Click "Settings" in sidebar
- Should see same submenu
4. Test in Standalone Mode
- Go to
/admin - Click "Settings" in sidebar
- Should see same submenu
5. Verify Backend Data
Open browser console and check:
console.log(window.WNW_NAV_TREE);
// Should show array with settings.children populated
📊 Before vs After
Before ❌
wp-admin mode:
Settings
└── (no submenu)
fullscreen mode:
Settings
└── (no submenu)
standalone mode:
Settings
├── WooNooW
├── General
├── Payments
└── ... (all items)
After ✅
ALL MODES:
Settings
├── WooNooW
├── General
├── Payments
├── Shipping
├── Products
├── Tax
├── Accounts & Privacy
├── Emails
├── Advanced (bridge)
├── Integration (bridge)
├── Status (bridge)
└── Extensions (bridge)
🔧 Files Modified
Backend
- ✅
includes/Compat/NavigationRegistry.php- Added
get_settings_children()method - Updated
get_base_tree()to use it
- Added
Frontend
- ✅
admin-spa/src/nav/tree.ts(already correct from previous fix) - ✅
admin-spa/src/types/window.d.ts(TypeScript types)
Documentation
- ✅
SETTINGS_TREE_PLAN.md(new - comprehensive implementation plan) - ✅
MENU_FIX_SUMMARY.md(this document)
🎯 Key Learnings
1. Dynamic Navigation System
WooNooW uses a dynamic navigation system where:
- Backend (PHP) builds the tree
- Frontend (TypeScript) consumes it
- Addons can extend via filters
2. Cache Awareness
Navigation tree is cached in wnw_nav_tree option:
- Rebuilt on
inithook - Flushed on plugin activate/deactivate
- Can be manually flushed:
delete_option('wnw_nav_tree')
3. Extensibility
Addons can modify navigation via filters:
// Add new main section
add_filter('woonoow/nav_tree', function($tree) {
$tree[] = [
'key' => 'subscriptions',
'label' => 'Subscriptions',
'path' => '/subscriptions',
'icon' => 'repeat',
'children' => [...]
];
return $tree;
});
// Add to existing section
add_filter('woonoow/nav_tree/settings/children', function($children) {
$children[] = [
'label' => 'My Custom Setting',
'mode' => 'spa',
'path' => '/settings/custom'
];
return $children;
});
✅ Verification Checklist
- Backend provides settings children
- Frontend reads from backend
- Fallback tree matches backend
- TypeScript types updated
- No console errors
- Settings submenu shows in all modes
- Bridge links work
- Documentation updated
- Code committed
🚀 Next Steps
-
Test the fix:
- Reload wp-admin page
- Check settings submenu appears
- Test in all three modes
-
Implement settings pages:
- Start with Phase 1 (General, Payments, Shipping)
- Follow
SETTINGS_TREE_PLAN.md
-
Monitor for issues:
- Check browser console
- Test with different user roles
- Verify 3rd party plugin compatibility
Fix Date: November 5, 2025
Status: ✅ Complete
Tested: Pending user verification
Next: Implement General Settings page