feat: migrate from HashRouter to BrowserRouter for SEO

Phase 1: WordPress Rewrite Rules
- Add rewrite rule for /store/* to serve SPA page
- Add use_browser_router setting toggle (default: true)
- Flush rewrite rules on settings change

Phase 2: React Router Migration
- Add BrowserRouter with basename from WordPress config
- Pass basePath and useBrowserRouter to frontend
- Conditional router based on setting

Phase 3: Hash Route Migration
- Update EmailManager.php reset password URL
- Update EmailRenderer.php login URL
- Update TemplateOverride.php WC redirects
- All routes now use path format by default

This enables proper SEO indexing as search engines
can now crawl individual product/page URLs.
This commit is contained in:
Dwindi Ramadhana
2026-01-03 20:01:32 +07:00
parent 0421e5010f
commit 45fcbf9d29
5 changed files with 118 additions and 13 deletions

View File

@@ -331,6 +331,7 @@ class EmailManager {
// The SPA page (e.g., /store/) loads customer-spa which has /reset-password route
$appearance_settings = get_option('woonoow_appearance_settings', []);
$spa_page_id = $appearance_settings['general']['spa_page'] ?? 0;
$use_browser_router = $appearance_settings['general']['use_browser_router'] ?? true;
if ($spa_page_id > 0) {
$spa_url = get_permalink($spa_page_id);
@@ -339,9 +340,15 @@ class EmailManager {
$spa_url = home_url('/');
}
// Build SPA reset password URL with hash router format
// Format: /store/#/reset-password?key=KEY&login=LOGIN
$reset_link = rtrim($spa_url, '/') . '#/reset-password?key=' . $key . '&login=' . rawurlencode($user_login);
// Build SPA reset password URL
// Use path format for BrowserRouter (SEO), hash format for HashRouter (legacy)
if ($use_browser_router) {
// Path format: /store/reset-password?key=KEY&login=LOGIN
$reset_link = trailingslashit($spa_url) . 'reset-password?key=' . $key . '&login=' . rawurlencode($user_login);
} else {
// Hash format: /store/#/reset-password?key=KEY&login=LOGIN
$reset_link = rtrim($spa_url, '/') . '#/reset-password?key=' . $key . '&login=' . rawurlencode($user_login);
}
// Create a pseudo WC_Customer for template rendering
$customer = null;

View File

@@ -259,7 +259,17 @@ class EmailRenderer {
// Generate login URL (pointing to SPA login instead of wp-login)
$appearance_settings = get_option('woonoow_appearance_settings', []);
$spa_page_id = $appearance_settings['general']['spa_page'] ?? 0;
$login_url = $spa_page_id ? get_permalink($spa_page_id) . '#/login' : wp_login_url();
$use_browser_router = $appearance_settings['general']['use_browser_router'] ?? true;
if ($spa_page_id) {
$spa_url = get_permalink($spa_page_id);
// Use path format for BrowserRouter, hash format for HashRouter
$login_url = $use_browser_router
? trailingslashit($spa_url) . 'login'
: $spa_url . '#/login';
} else {
$login_url = wp_login_url();
}
$variables = array_merge($variables, [
'customer_id' => $data->get_id(),