feat: Dynamic SPA slug, field label storage, and SPA frontpage support (WIP)
This commit is contained in:
@@ -35,6 +35,9 @@ class TemplateOverride
|
||||
// Redirect WooCommerce pages to SPA routes early (before template loads)
|
||||
add_action('template_redirect', [__CLASS__, 'redirect_wc_pages_to_spa'], 5);
|
||||
|
||||
// Serve SPA directly for frontpage routes (priority 1 = very early, before WC)
|
||||
add_action('template_redirect', [__CLASS__, 'serve_spa_for_frontpage_routes'], 1);
|
||||
|
||||
// Hook to wp_loaded with priority 10 (BEFORE WooCommerce's priority 20)
|
||||
// This ensures we process add-to-cart before WooCommerce does
|
||||
add_action('wp_loaded', [__CLASS__, 'intercept_add_to_cart'], 10);
|
||||
@@ -68,7 +71,7 @@ class TemplateOverride
|
||||
|
||||
/**
|
||||
* Register rewrite rules for BrowserRouter SEO
|
||||
* Catches all /store/* routes and serves the SPA page
|
||||
* Catches all SPA routes and serves the SPA page
|
||||
*/
|
||||
public static function register_spa_rewrite_rules()
|
||||
{
|
||||
@@ -89,13 +92,82 @@ class TemplateOverride
|
||||
|
||||
$spa_slug = $spa_page->post_name;
|
||||
|
||||
// Rewrite /store/anything to serve the SPA page
|
||||
// React Router handles the path after that
|
||||
add_rewrite_rule(
|
||||
'^' . preg_quote($spa_slug, '/') . '/(.*)$',
|
||||
'index.php?page_id=' . $spa_page_id . '&woonoow_spa_path=$matches[1]',
|
||||
'top'
|
||||
);
|
||||
// Check if SPA page is set as WordPress frontpage
|
||||
$frontpage_id = (int) get_option('page_on_front');
|
||||
$is_spa_frontpage = $frontpage_id && $frontpage_id === (int) $spa_page_id;
|
||||
|
||||
if ($is_spa_frontpage) {
|
||||
// When SPA is frontpage, add root-level routes
|
||||
// /shop, /shop/* → SPA page
|
||||
add_rewrite_rule(
|
||||
'^shop/?$',
|
||||
'index.php?page_id=' . $spa_page_id . '&woonoow_spa_path=shop',
|
||||
'top'
|
||||
);
|
||||
add_rewrite_rule(
|
||||
'^shop/(.*)$',
|
||||
'index.php?page_id=' . $spa_page_id . '&woonoow_spa_path=shop/$matches[1]',
|
||||
'top'
|
||||
);
|
||||
|
||||
// /product/* → SPA page
|
||||
add_rewrite_rule(
|
||||
'^product/(.*)$',
|
||||
'index.php?page_id=' . $spa_page_id . '&woonoow_spa_path=product/$matches[1]',
|
||||
'top'
|
||||
);
|
||||
|
||||
// /cart → SPA page
|
||||
add_rewrite_rule(
|
||||
'^cart/?$',
|
||||
'index.php?page_id=' . $spa_page_id . '&woonoow_spa_path=cart',
|
||||
'top'
|
||||
);
|
||||
|
||||
// /checkout → SPA page
|
||||
add_rewrite_rule(
|
||||
'^checkout/?$',
|
||||
'index.php?page_id=' . $spa_page_id . '&woonoow_spa_path=checkout',
|
||||
'top'
|
||||
);
|
||||
|
||||
// /my-account, /my-account/* → SPA page
|
||||
add_rewrite_rule(
|
||||
'^my-account/?$',
|
||||
'index.php?page_id=' . $spa_page_id . '&woonoow_spa_path=my-account',
|
||||
'top'
|
||||
);
|
||||
add_rewrite_rule(
|
||||
'^my-account/(.*)$',
|
||||
'index.php?page_id=' . $spa_page_id . '&woonoow_spa_path=my-account/$matches[1]',
|
||||
'top'
|
||||
);
|
||||
|
||||
// /login, /register, /reset-password → SPA page
|
||||
add_rewrite_rule(
|
||||
'^login/?$',
|
||||
'index.php?page_id=' . $spa_page_id . '&woonoow_spa_path=login',
|
||||
'top'
|
||||
);
|
||||
add_rewrite_rule(
|
||||
'^register/?$',
|
||||
'index.php?page_id=' . $spa_page_id . '&woonoow_spa_path=register',
|
||||
'top'
|
||||
);
|
||||
add_rewrite_rule(
|
||||
'^reset-password/?$',
|
||||
'index.php?page_id=' . $spa_page_id . '&woonoow_spa_path=reset-password',
|
||||
'top'
|
||||
);
|
||||
} else {
|
||||
// Rewrite /slug/anything to serve the SPA page
|
||||
// React Router handles the path after that
|
||||
add_rewrite_rule(
|
||||
'^' . preg_quote($spa_slug, '/') . '/(.*)$',
|
||||
'index.php?page_id=' . $spa_page_id . '&woonoow_spa_path=$matches[1]',
|
||||
'top'
|
||||
);
|
||||
}
|
||||
|
||||
// Register query var for the SPA path
|
||||
add_filter('query_vars', function($vars) {
|
||||
@@ -174,6 +246,12 @@ class TemplateOverride
|
||||
return; // No SPA page configured
|
||||
}
|
||||
|
||||
// Skip if SPA is set as frontpage (serve_spa_for_frontpage_routes handles it)
|
||||
$frontpage_id = (int) get_option('page_on_front');
|
||||
if ($frontpage_id && $frontpage_id === (int) $spa_page_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Already on SPA page, don't redirect
|
||||
global $post;
|
||||
if ($post && $post->ID == $spa_page_id) {
|
||||
@@ -224,6 +302,88 @@ class TemplateOverride
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serve SPA template directly for frontpage SPA routes
|
||||
* When SPA page is set as WordPress frontpage, intercept known routes
|
||||
* and serve the SPA template directly (bypasses WooCommerce templates)
|
||||
*/
|
||||
public static function serve_spa_for_frontpage_routes()
|
||||
{
|
||||
// Get SPA settings
|
||||
$appearance_settings = get_option('woonoow_appearance_settings', []);
|
||||
$spa_page_id = $appearance_settings['general']['spa_page'] ?? 0;
|
||||
$spa_mode = $appearance_settings['general']['spa_mode'] ?? 'full';
|
||||
|
||||
// Only run in full SPA mode
|
||||
if ($spa_mode !== 'full' || !$spa_page_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if SPA page is set as WordPress frontpage
|
||||
$frontpage_id = (int) get_option('page_on_front');
|
||||
if (!$frontpage_id || $frontpage_id !== (int) $spa_page_id) {
|
||||
return; // SPA is not frontpage, let normal routing handle it
|
||||
}
|
||||
|
||||
// Get the current request path
|
||||
$request_uri = $_SERVER['REQUEST_URI'] ?? '/';
|
||||
$path = parse_url($request_uri, PHP_URL_PATH);
|
||||
$path = '/' . trim($path, '/');
|
||||
|
||||
// Define SPA routes that should be intercepted when SPA is frontpage
|
||||
$spa_routes = [
|
||||
'/', // Frontpage itself
|
||||
'/shop', // Shop page
|
||||
'/cart', // Cart page
|
||||
'/checkout', // Checkout page
|
||||
'/my-account', // Account page
|
||||
'/login', // Login page
|
||||
'/register', // Register page
|
||||
'/reset-password', // Password reset
|
||||
];
|
||||
|
||||
// Check for exact matches or path prefixes
|
||||
$should_serve_spa = false;
|
||||
|
||||
// Check exact matches
|
||||
if (in_array($path, $spa_routes)) {
|
||||
$should_serve_spa = true;
|
||||
}
|
||||
|
||||
// Check path prefixes (for sub-routes)
|
||||
$prefix_routes = ['/shop/', '/my-account/', '/product/'];
|
||||
foreach ($prefix_routes as $prefix) {
|
||||
if (strpos($path, $prefix) === 0) {
|
||||
$should_serve_spa = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Not a SPA route
|
||||
if (!$should_serve_spa) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent caching for dynamic SPA content
|
||||
nocache_headers();
|
||||
|
||||
// Load the SPA template directly and exit
|
||||
$spa_template = plugin_dir_path(dirname(dirname(__FILE__))) . 'templates/spa-full-page.php';
|
||||
if (file_exists($spa_template)) {
|
||||
// Set up minimal WordPress environment for the template
|
||||
status_header(200);
|
||||
|
||||
// Define constant to tell Assets to load unconditionally
|
||||
if (!defined('WOONOOW_SERVE_SPA')) {
|
||||
define('WOONOOW_SERVE_SPA', true);
|
||||
}
|
||||
|
||||
// Include the SPA template
|
||||
include $spa_template;
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable canonical redirects for SPA routes
|
||||
* This prevents WordPress from redirecting /product/slug URLs
|
||||
@@ -406,17 +566,25 @@ class TemplateOverride
|
||||
private static function is_spa_page()
|
||||
{
|
||||
global $post;
|
||||
if (!$post) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Get SPA settings from appearance
|
||||
$appearance_settings = get_option('woonoow_appearance_settings', []);
|
||||
$spa_page_id = $appearance_settings['general']['spa_page'] ?? 0;
|
||||
$spa_mode = $appearance_settings['general']['spa_mode'] ?? 'full';
|
||||
|
||||
// Only return true if spa_mode is 'full' AND we're on the SPA page
|
||||
if ($spa_mode === 'full' && $spa_page_id && $post->ID == $spa_page_id) {
|
||||
// Only check if spa_mode is 'full' and SPA page is configured
|
||||
if ($spa_mode !== 'full' || !$spa_page_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if current page is the SPA page
|
||||
if ($post && $post->ID == $spa_page_id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if SPA page is set as WordPress frontpage and we're on frontpage
|
||||
$frontpage_id = (int) get_option('page_on_front');
|
||||
if ($frontpage_id && $frontpage_id === (int) $spa_page_id && is_front_page()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user