# Fix: Direct URL Access Shows 404 Page ## Problem - ✅ Navigation from shop page works → Shows SPA - ❌ Direct URL access fails → Shows WordPress theme 404 page **Example:** - Click product from shop: `https://woonoow.local/product/edukasi-anak` ✅ Works - Type URL directly: `https://woonoow.local/product/edukasi-anak` ❌ Shows 404 ## Why Admin SPA Works But Customer SPA Doesn't ### Admin SPA ``` URL: /wp-admin/admin.php?page=woonoow ↓ WordPress Admin Area (always controlled) ↓ Admin menu system loads the SPA ↓ Works perfectly ✅ ``` ### Customer SPA (Before Fix) ``` URL: /product/edukasi-anak ↓ WordPress: "Is this a post/page?" ↓ WordPress: "No post found with slug 'edukasi-anak'" ↓ WordPress: "Return 404 template" ↓ Theme's 404.php loads ❌ ↓ SPA never gets a chance to load ``` ## Root Cause When you access `/product/edukasi-anak` directly: 1. **WordPress query runs** - Looks for a post with slug `edukasi-anak` 2. **No post found** - Because it's a React Router route, not a WordPress post 3. **`is_product()` returns false** - WordPress doesn't think it's a product page 4. **404 template loads** - Theme's 404.php takes over 5. **SPA template never loads** - Our `use_spa_template` filter doesn't trigger ### Why Navigation Works When you click from shop page: 1. React Router handles the navigation (client-side) 2. No page reload 3. No WordPress query 4. React Router shows the Product component 5. Everything works ✅ ## Solution Detect SPA routes **by URL** before WordPress determines it's a 404. ### Implementation **File:** `includes/Frontend/TemplateOverride.php` ```php public static function use_spa_template($template) { $settings = get_option('woonoow_customer_spa_settings', []); $mode = isset($settings['mode']) ? $settings['mode'] : 'disabled'; if ($mode === 'disabled') { return $template; } // Check if current URL is a SPA route (for direct access) $request_uri = $_SERVER['REQUEST_URI']; $spa_routes = ['/shop', '/product/', '/cart', '/checkout', '/my-account']; $is_spa_route = false; foreach ($spa_routes as $route) { if (strpos($request_uri, $route) !== false) { $is_spa_route = true; break; } } // If it's a SPA route in full mode, use SPA template if ($mode === 'full' && $is_spa_route) { $spa_template = plugin_dir_path(dirname(dirname(__FILE__))) . 'templates/spa-full-page.php'; if (file_exists($spa_template)) { // Set status to 200 to prevent 404 status_header(200); return $spa_template; } } // ... rest of the code } ``` ## How It Works ### New Flow (After Fix) ``` URL: /product/edukasi-anak ↓ WordPress: "Should I use default template?" ↓ Our filter: "Wait! Check the URL..." ↓ Our filter: "URL contains '/product/' → This is a SPA route" ↓ Our filter: "Return SPA template instead" ↓ status_header(200) → Set HTTP status to 200 (not 404) ↓ SPA template loads ✅ ↓ React Router handles /product/edukasi-anak ↓ Product page displays correctly ✅ ``` ## Key Changes ### 1. URL-Based Detection ```php $request_uri = $_SERVER['REQUEST_URI']; $spa_routes = ['/shop', '/product/', '/cart', '/checkout', '/my-account']; foreach ($spa_routes as $route) { if (strpos($request_uri, $route) !== false) { $is_spa_route = true; break; } } ``` **Why:** Detects SPA routes before WordPress query runs. ### 2. Force 200 Status ```php status_header(200); ``` **Why:** Prevents WordPress from setting 404 status, which would affect SEO and browser behavior. ### 3. Early Return ```php if ($mode === 'full' && $is_spa_route) { return $spa_template; } ``` **Why:** Returns SPA template immediately, bypassing WordPress's normal template hierarchy. ## Comparison: Admin vs Customer SPA | Aspect | Admin SPA | Customer SPA | |--------|-----------|--------------| | **Location** | `/wp-admin/` | Frontend URLs | | **Template Control** | Always controlled by WP | Must override theme | | **URL Detection** | Menu system | URL pattern matching | | **404 Risk** | None | High (before fix) | | **Complexity** | Simple | More complex | ## Why This Approach Works ### 1. Catches Direct Access URL-based detection works for both: - Direct browser access - Bookmarks - External links - Copy-paste URLs ### 2. Doesn't Break Navigation Client-side navigation still works because: - React Router handles it - No page reload - No WordPress query ### 3. SEO Safe - Sets proper 200 status - No 404 errors - Search engines see valid pages ### 4. Theme Independent - Doesn't rely on theme templates - Works with any WordPress theme - No theme modifications needed ## Testing ### Test 1: Direct Access 1. Open new browser tab 2. Type: `https://woonoow.local/product/edukasi-anak` 3. Press Enter 4. **Expected:** Product page loads with SPA 5. **Should NOT see:** Theme's 404 page ### Test 2: Refresh 1. Navigate to product page from shop 2. Press F5 (refresh) 3. **Expected:** Page reloads and shows product 4. **Should NOT:** Redirect or show 404 ### Test 3: Bookmark 1. Bookmark a product page 2. Close browser 3. Open bookmark 4. **Expected:** Product page loads directly ### Test 4: All Routes Test each SPA route: - `/shop` ✅ - `/product/any-slug` ✅ - `/cart` ✅ - `/checkout` ✅ - `/my-account` ✅ ## Debugging ### Check Template Loading Add to `spa-full-page.php`: ```php ``` ### Check Status Code In browser console: ```javascript console.log('Status:', performance.getEntriesByType('navigation')[0].responseStatus); ``` Should be `200`, not `404`. ## Alternative Approaches (Not Used) ### Option 1: Custom Post Type Create a custom post type for products. **Pros:** WordPress recognizes URLs **Cons:** Duplicates WooCommerce products, complex sync ### Option 2: Rewrite Rules Add custom rewrite rules. **Pros:** More "WordPress way" **Cons:** Requires flush_rewrite_rules(), can conflict ### Option 3: Hash Router Use `#` in URLs. **Pros:** No server-side changes needed **Cons:** Ugly URLs, poor SEO ### Our Solution: URL Detection ✅ **Pros:** - Simple - Reliable - No conflicts - SEO friendly - Works immediately **Cons:** None! ## Summary **Problem:** Direct URL access shows 404 because WordPress doesn't recognize SPA routes **Root Cause:** WordPress query runs before SPA template can load **Solution:** Detect SPA routes by URL pattern and return SPA template with 200 status **Result:** Direct access now works perfectly! ✅ **Files Modified:** - `includes/Frontend/TemplateOverride.php` - Added URL-based detection **Test:** Type `/product/edukasi-anak` directly in browser - should work!