finalizing subscription moduile, ready to test
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace WooNooW\Frontend;
|
||||
|
||||
use WooNooW\Frontend\PageSSR;
|
||||
@@ -18,32 +19,32 @@ class TemplateOverride
|
||||
{
|
||||
// Register rewrite rules for BrowserRouter SEO (must be on 'init')
|
||||
add_action('init', [__CLASS__, 'register_spa_rewrite_rules']);
|
||||
|
||||
|
||||
// Flush rewrite rules when relevant settings change
|
||||
add_action('update_option_woonoow_appearance_settings', function($old_value, $new_value) {
|
||||
add_action('update_option_woonoow_appearance_settings', function ($old_value, $new_value) {
|
||||
$old_general = $old_value['general'] ?? [];
|
||||
$new_general = $new_value['general'] ?? [];
|
||||
|
||||
|
||||
// Only flush if spa_mode, spa_page, or use_browser_router changed
|
||||
$needs_flush =
|
||||
$needs_flush =
|
||||
($old_general['spa_mode'] ?? '') !== ($new_general['spa_mode'] ?? '') ||
|
||||
($old_general['spa_page'] ?? '') !== ($new_general['spa_page'] ?? '') ||
|
||||
($old_general['use_browser_router'] ?? true) !== ($new_general['use_browser_router'] ?? true);
|
||||
|
||||
|
||||
if ($needs_flush) {
|
||||
flush_rewrite_rules();
|
||||
}
|
||||
}, 10, 2);
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
|
||||
// Serve SSR for bots on pages/CPT with WooNooW structure (priority 2 = after frontpage check)
|
||||
add_action('template_redirect', [__CLASS__, 'maybe_serve_ssr_for_bots'], 2);
|
||||
|
||||
|
||||
// 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);
|
||||
@@ -74,7 +75,7 @@ class TemplateOverride
|
||||
add_action('get_header', [__CLASS__, 'remove_theme_header']);
|
||||
add_action('get_footer', [__CLASS__, 'remove_theme_footer']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register rewrite rules for BrowserRouter SEO
|
||||
* Catches all SPA routes and serves the SPA page
|
||||
@@ -83,25 +84,25 @@ class TemplateOverride
|
||||
{
|
||||
$appearance_settings = get_option('woonoow_appearance_settings', []);
|
||||
$spa_page_id = $appearance_settings['general']['spa_page'] ?? 0;
|
||||
|
||||
|
||||
// Check if BrowserRouter is enabled (default: true for new installs)
|
||||
$use_browser_router = $appearance_settings['general']['use_browser_router'] ?? true;
|
||||
|
||||
|
||||
if (!$spa_page_id || !$use_browser_router) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$spa_page = get_post($spa_page_id);
|
||||
if (!$spa_page) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$spa_slug = $spa_page->post_name;
|
||||
|
||||
|
||||
// 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
|
||||
@@ -115,28 +116,33 @@ class TemplateOverride
|
||||
'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
|
||||
|
||||
// /checkout, /checkout/* → SPA page
|
||||
add_rewrite_rule(
|
||||
'^checkout/?$',
|
||||
'index.php?page_id=' . $spa_page_id . '&woonoow_spa_path=checkout',
|
||||
'top'
|
||||
);
|
||||
|
||||
add_rewrite_rule(
|
||||
'^checkout/(.*)$',
|
||||
'index.php?page_id=' . $spa_page_id . '&woonoow_spa_path=checkout/$matches[1]',
|
||||
'top'
|
||||
);
|
||||
|
||||
// /my-account, /my-account/* → SPA page
|
||||
add_rewrite_rule(
|
||||
'^my-account/?$',
|
||||
@@ -148,7 +154,7 @@ class TemplateOverride
|
||||
'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/?$',
|
||||
@@ -165,6 +171,24 @@ class TemplateOverride
|
||||
'index.php?page_id=' . $spa_page_id . '&woonoow_spa_path=reset-password',
|
||||
'top'
|
||||
);
|
||||
|
||||
// /order-pay/* → SPA page
|
||||
add_rewrite_rule(
|
||||
'^order-pay/(.*)$',
|
||||
'index.php?page_id=' . $spa_page_id . '&woonoow_spa_path=order-pay/$matches[1]',
|
||||
'top'
|
||||
);
|
||||
|
||||
// /order-pay/* → SPA page
|
||||
add_rewrite_rule(
|
||||
'^order-pay/(.*)$',
|
||||
'index.php?page_id=' . $spa_page_id . '&woonoow_spa_path=order-pay/$matches[1]',
|
||||
'top'
|
||||
);
|
||||
|
||||
// /order-pay/* → SPA page (moved to checkout/pay/ in new structure)
|
||||
// Removed direct order-pay rule to favor checkout subpath
|
||||
|
||||
} else {
|
||||
// Rewrite /slug to serve the SPA page (base URL)
|
||||
add_rewrite_rule(
|
||||
@@ -172,7 +196,7 @@ class TemplateOverride
|
||||
'index.php?page_id=' . $spa_page_id,
|
||||
'top'
|
||||
);
|
||||
|
||||
|
||||
// Rewrite /slug/anything to serve the SPA page with path
|
||||
// React Router handles the path after that
|
||||
add_rewrite_rule(
|
||||
@@ -181,9 +205,9 @@ class TemplateOverride
|
||||
'top'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Register query var for the SPA path
|
||||
add_filter('query_vars', function($vars) {
|
||||
add_filter('query_vars', function ($vars) {
|
||||
$vars[] = 'woonoow_spa_path';
|
||||
return $vars;
|
||||
});
|
||||
@@ -249,32 +273,32 @@ class TemplateOverride
|
||||
$spa_page_id = $appearance_settings['general']['spa_page'] ?? 0;
|
||||
$spa_mode = $appearance_settings['general']['spa_mode'] ?? 'full';
|
||||
$use_browser_router = $appearance_settings['general']['use_browser_router'] ?? true;
|
||||
|
||||
|
||||
// Only redirect when SPA mode is 'full'
|
||||
if ($spa_mode !== 'full') {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!$spa_page_id) {
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$spa_url = trailingslashit(get_permalink($spa_page_id));
|
||||
|
||||
|
||||
// Helper function to build route URL based on router type
|
||||
$build_route = function($path) use ($spa_url, $use_browser_router) {
|
||||
$build_route = function ($path) use ($spa_url, $use_browser_router) {
|
||||
if ($use_browser_router) {
|
||||
// Path format: /store/cart
|
||||
return $spa_url . ltrim($path, '/');
|
||||
@@ -282,13 +306,13 @@ class TemplateOverride
|
||||
// Hash format: /store/#/cart
|
||||
return rtrim($spa_url, '/') . '#/' . ltrim($path, '/');
|
||||
};
|
||||
|
||||
|
||||
// Check which WC page we're on and redirect
|
||||
if (is_shop()) {
|
||||
wp_redirect($build_route('shop'), 302);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
if (is_product()) {
|
||||
// Use get_queried_object() which returns the WP_Post, then get slug
|
||||
$product_post = get_queried_object();
|
||||
@@ -298,29 +322,37 @@ class TemplateOverride
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (is_cart()) {
|
||||
wp_redirect($build_route('cart'), 302);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
if (is_checkout() && !is_order_received_page()) {
|
||||
// Check for order-pay endpoint
|
||||
if (is_wc_endpoint_url('order-pay')) {
|
||||
global $wp;
|
||||
$order_id = $wp->query_vars['order-pay'];
|
||||
wp_redirect($build_route('order-pay/' . $order_id), 302);
|
||||
exit;
|
||||
}
|
||||
|
||||
wp_redirect($build_route('checkout'), 302);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
if (is_account_page()) {
|
||||
wp_redirect($build_route('my-account'), 302);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
// Redirect structural pages with WooNooW sections to SPA
|
||||
if (is_singular('page') && $post) {
|
||||
// Skip the SPA page itself and frontpage
|
||||
if ($post->ID == $spa_page_id || $post->ID == $frontpage_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Check if page has WooNooW structure
|
||||
$structure = get_post_meta($post->ID, '_wn_page_structure', true);
|
||||
if (!empty($structure) && !empty($structure['sections'])) {
|
||||
@@ -348,22 +380,22 @@ class TemplateOverride
|
||||
$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 relative to site root
|
||||
$request_uri = $_SERVER['REQUEST_URI'] ?? '/';
|
||||
$home_path = parse_url(home_url(), PHP_URL_PATH);
|
||||
|
||||
|
||||
// Normalize request URI for subdirectory installs
|
||||
if ($home_path && $home_path !== '/') {
|
||||
$home_path = rtrim($home_path, '/');
|
||||
@@ -375,7 +407,7 @@ class TemplateOverride
|
||||
|
||||
$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
|
||||
@@ -385,37 +417,39 @@ class TemplateOverride
|
||||
'/my-account', // Account page
|
||||
'/login', // Login page
|
||||
'/register', // Register page
|
||||
'/register', // Register page
|
||||
'/reset-password', // Password reset
|
||||
'/order-pay', // Order pay page
|
||||
];
|
||||
|
||||
|
||||
// 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/'];
|
||||
$prefix_routes = ['/shop/', '/my-account/', '/product/', '/checkout/'];
|
||||
foreach ($prefix_routes as $prefix) {
|
||||
if (strpos($path, $prefix) === 0) {
|
||||
$should_serve_spa = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check for structural pages with WooNooW sections
|
||||
if (!$should_serve_spa && !empty($path) && $path !== '/') {
|
||||
// Try to find a page by slug matching the path
|
||||
$slug = trim($path, '/');
|
||||
|
||||
|
||||
// Handle nested slugs (get the last part as the page slug)
|
||||
if (strpos($slug, '/') !== false) {
|
||||
$slug_parts = explode('/', $slug);
|
||||
$slug = end($slug_parts);
|
||||
}
|
||||
|
||||
|
||||
$page = get_page_by_path($slug);
|
||||
if ($page) {
|
||||
// Check if this page has WooNooW structure
|
||||
@@ -425,26 +459,26 @@ class TemplateOverride
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
@@ -487,12 +521,12 @@ class TemplateOverride
|
||||
// Check spa_mode from appearance settings FIRST
|
||||
$appearance_settings = get_option('woonoow_appearance_settings', []);
|
||||
$spa_mode = $appearance_settings['general']['spa_mode'] ?? 'full';
|
||||
|
||||
|
||||
// If SPA is disabled, return original template immediately
|
||||
if ($spa_mode === 'disabled') {
|
||||
return $template;
|
||||
}
|
||||
|
||||
|
||||
// Check if current page is a designated SPA page
|
||||
if (self::is_spa_page()) {
|
||||
$spa_template = plugin_dir_path(dirname(dirname(__FILE__))) . 'templates/spa-full-page.php';
|
||||
@@ -511,7 +545,7 @@ class TemplateOverride
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// For spa_mode = 'checkout_only'
|
||||
if ($spa_mode === 'checkout_only') {
|
||||
if (is_checkout() || is_order_received_page() || is_account_page() || is_cart()) {
|
||||
@@ -634,7 +668,7 @@ class TemplateOverride
|
||||
private static function is_spa_page()
|
||||
{
|
||||
global $post;
|
||||
|
||||
|
||||
// Get SPA settings from appearance
|
||||
$appearance_settings = get_option('woonoow_appearance_settings', []);
|
||||
$spa_page_id = $appearance_settings['general']['spa_page'] ?? 0;
|
||||
@@ -716,7 +750,7 @@ class TemplateOverride
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detect if current request is from a bot/crawler
|
||||
* Used to serve SSR content for SEO instead of SPA redirect
|
||||
@@ -730,10 +764,10 @@ class TemplateOverride
|
||||
if (empty($user_agent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Convert to lowercase for case-insensitive matching
|
||||
$user_agent = strtolower($user_agent);
|
||||
|
||||
|
||||
// Known bot patterns
|
||||
$bot_patterns = [
|
||||
// Search engine crawlers
|
||||
@@ -745,13 +779,13 @@ class TemplateOverride
|
||||
'yandexbot',
|
||||
'sogou',
|
||||
'exabot',
|
||||
|
||||
|
||||
// Generic patterns
|
||||
'crawler',
|
||||
'spider',
|
||||
'robot',
|
||||
'scraper',
|
||||
|
||||
|
||||
// Social media bots (for link previews)
|
||||
'facebookexternalhit',
|
||||
'twitterbot',
|
||||
@@ -760,7 +794,7 @@ class TemplateOverride
|
||||
'slackbot',
|
||||
'telegrambot',
|
||||
'discordbot',
|
||||
|
||||
|
||||
// Other known bots
|
||||
'applebot',
|
||||
'semrushbot',
|
||||
@@ -769,22 +803,22 @@ class TemplateOverride
|
||||
'dotbot',
|
||||
'petalbot',
|
||||
'bytespider',
|
||||
|
||||
|
||||
// Prerender services
|
||||
'prerender',
|
||||
'headlesschrome',
|
||||
];
|
||||
|
||||
|
||||
// Check if User-Agent contains any bot pattern
|
||||
foreach ($bot_patterns as $pattern) {
|
||||
if (strpos($user_agent, $pattern) !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serve SSR content for bots
|
||||
* Renders page structure as static HTML for search engine indexing
|
||||
@@ -798,17 +832,17 @@ class TemplateOverride
|
||||
// Generate cache key
|
||||
$cache_id = $post_obj ? $post_obj->ID : $page_id;
|
||||
$cache_key = "wn_ssr_{$type}_{$cache_id}";
|
||||
|
||||
|
||||
// Check cache TTL (default 1 hour, filterable)
|
||||
$cache_ttl = apply_filters('woonoow_ssr_cache_ttl', HOUR_IN_SECONDS);
|
||||
|
||||
|
||||
// Try to get cached content
|
||||
$cached = get_transient($cache_key);
|
||||
if ($cached !== false) {
|
||||
echo $cached;
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
// Get page structure
|
||||
if ($type === 'page') {
|
||||
$structure = get_post_meta($page_id, '_wn_page_structure', true);
|
||||
@@ -816,103 +850,155 @@ class TemplateOverride
|
||||
// CPT template - type is the post_type like 'post', 'portfolio', etc.
|
||||
$structure = get_option("wn_template_{$type}", null);
|
||||
}
|
||||
|
||||
|
||||
if (empty($structure) || empty($structure['sections'])) {
|
||||
return false; // No structure, let normal WP handle it
|
||||
}
|
||||
|
||||
|
||||
// Render using PageSSR
|
||||
$post_data = null;
|
||||
if ($post_obj && $type !== 'page') {
|
||||
$placeholder_renderer = new PlaceholderRenderer();
|
||||
$post_data = $placeholder_renderer->build_post_data($post_obj);
|
||||
}
|
||||
|
||||
|
||||
$ssr = new PageSSR();
|
||||
$html = $ssr->render($structure['sections'], $post_data);
|
||||
|
||||
|
||||
if (empty($html)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Get page title
|
||||
$title = $type === 'page' ? get_the_title($page_id) : '';
|
||||
if ($post_obj) {
|
||||
$title = get_the_title($post_obj);
|
||||
}
|
||||
|
||||
|
||||
// SEO data
|
||||
$seo_title = $title . ' - ' . get_bloginfo('name');
|
||||
$seo_description = '';
|
||||
|
||||
|
||||
// Try to get Yoast/Rank Math SEO data
|
||||
if ($type === 'page') {
|
||||
$seo_title = get_post_meta($page_id, '_yoast_wpseo_title', true) ?:
|
||||
get_post_meta($page_id, 'rank_math_title', true) ?: $seo_title;
|
||||
$seo_description = get_post_meta($page_id, '_yoast_wpseo_metadesc', true) ?:
|
||||
get_post_meta($page_id, 'rank_math_description', true) ?: '';
|
||||
$seo_title = get_post_meta($page_id, '_yoast_wpseo_title', true) ?:
|
||||
get_post_meta($page_id, 'rank_math_title', true) ?: $seo_title;
|
||||
$seo_description = get_post_meta($page_id, '_yoast_wpseo_metadesc', true) ?:
|
||||
get_post_meta($page_id, 'rank_math_description', true) ?: '';
|
||||
} elseif ($post_obj) {
|
||||
$seo_title = get_post_meta($post_obj->ID, '_yoast_wpseo_title', true) ?:
|
||||
get_post_meta($post_obj->ID, 'rank_math_title', true) ?: $seo_title;
|
||||
$seo_description = get_post_meta($post_obj->ID, '_yoast_wpseo_metadesc', true) ?:
|
||||
get_post_meta($post_obj->ID, 'rank_math_description', true) ?:
|
||||
wp_trim_words(wp_strip_all_tags($post_obj->post_content), 30);
|
||||
$seo_title = get_post_meta($post_obj->ID, '_yoast_wpseo_title', true) ?:
|
||||
get_post_meta($post_obj->ID, 'rank_math_title', true) ?: $seo_title;
|
||||
$seo_description = get_post_meta($post_obj->ID, '_yoast_wpseo_metadesc', true) ?:
|
||||
get_post_meta($post_obj->ID, 'rank_math_description', true) ?:
|
||||
wp_trim_words(wp_strip_all_tags($post_obj->post_content), 30);
|
||||
}
|
||||
|
||||
|
||||
// Output SSR HTML - start output buffering for caching
|
||||
ob_start();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html <?php language_attributes(); ?>>
|
||||
<head>
|
||||
<meta charset="<?php bloginfo('charset'); ?>">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><?php echo esc_html($seo_title); ?></title>
|
||||
<?php if ($seo_description): ?>
|
||||
<meta name="description" content="<?php echo esc_attr($seo_description); ?>">
|
||||
<?php endif; ?>
|
||||
<link rel="canonical" href="<?php echo esc_url(get_permalink($post_obj ?: $page_id)); ?>">
|
||||
<meta property="og:title" content="<?php echo esc_attr($seo_title); ?>">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="<?php echo esc_url(get_permalink($post_obj ?: $page_id)); ?>">
|
||||
<?php if ($seo_description): ?>
|
||||
<meta property="og:description" content="<?php echo esc_attr($seo_description); ?>">
|
||||
<?php endif; ?>
|
||||
<style>
|
||||
/* Minimal SSR styles for bots */
|
||||
body { font-family: system-ui, -apple-system, sans-serif; line-height: 1.6; margin: 0; padding: 0; }
|
||||
.wn-ssr { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
.wn-section { padding: 40px 0; }
|
||||
.wn-section h1, .wn-section h2 { margin-bottom: 16px; }
|
||||
.wn-section p { margin-bottom: 12px; }
|
||||
.wn-section img { max-width: 100%; height: auto; }
|
||||
.wn-hero { background: #f5f5f5; padding: 60px 20px; text-align: center; }
|
||||
.wn-cta-banner { background: #4f46e5; color: white; padding: 40px 20px; text-align: center; }
|
||||
.wn-cta-banner a { color: white; text-decoration: underline; }
|
||||
.wn-feature-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 24px; }
|
||||
.wn-feature-item { padding: 20px; border: 1px solid #e5e5e5; border-radius: 8px; }
|
||||
</style>
|
||||
<?php wp_head(); ?>
|
||||
</head>
|
||||
<body <?php body_class('wn-ssr-page'); ?>>
|
||||
<div class="wn-ssr">
|
||||
<?php echo $html; ?>
|
||||
</div>
|
||||
<?php wp_footer(); ?>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html <?php language_attributes(); ?>>
|
||||
|
||||
<head>
|
||||
<meta charset="<?php bloginfo('charset'); ?>">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><?php echo esc_html($seo_title); ?></title>
|
||||
<?php if ($seo_description): ?>
|
||||
<meta name="description" content="<?php echo esc_attr($seo_description); ?>">
|
||||
<?php endif; ?>
|
||||
<link rel="canonical" href="<?php echo esc_url(get_permalink($post_obj ?: $page_id)); ?>">
|
||||
<meta property="og:title" content="<?php echo esc_attr($seo_title); ?>">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="<?php echo esc_url(get_permalink($post_obj ?: $page_id)); ?>">
|
||||
<?php if ($seo_description): ?>
|
||||
<meta property="og:description" content="<?php echo esc_attr($seo_description); ?>">
|
||||
<?php endif; ?>
|
||||
<style>
|
||||
/* Minimal SSR styles for bots */
|
||||
body {
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.wn-ssr {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.wn-section {
|
||||
padding: 40px 0;
|
||||
}
|
||||
|
||||
.wn-section h1,
|
||||
.wn-section h2 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.wn-section p {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.wn-section img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.wn-hero {
|
||||
background: #f5f5f5;
|
||||
padding: 60px 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wn-cta-banner {
|
||||
background: #4f46e5;
|
||||
color: white;
|
||||
padding: 40px 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wn-cta-banner a {
|
||||
color: white;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.wn-feature-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.wn-feature-item {
|
||||
padding: 20px;
|
||||
border: 1px solid #e5e5e5;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
<?php wp_head(); ?>
|
||||
</head>
|
||||
|
||||
<body <?php body_class('wn-ssr-page'); ?>>
|
||||
<div class="wn-ssr">
|
||||
<?php echo $html; ?>
|
||||
</div>
|
||||
<?php wp_footer(); ?>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<?php
|
||||
// Get buffered output
|
||||
$output = ob_get_clean();
|
||||
|
||||
|
||||
// Cache the output for bots (uses cache TTL from filter)
|
||||
set_transient($cache_key, $output, $cache_ttl);
|
||||
|
||||
|
||||
// Output and exit
|
||||
echo $output;
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle SSR for structural pages and CPT items when bot detected
|
||||
* Should be called from template_redirect hook
|
||||
@@ -923,22 +1009,22 @@ class TemplateOverride
|
||||
if (!self::is_bot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Check if this is a page with WooNooW structure
|
||||
if (is_singular('page')) {
|
||||
$page_id = get_queried_object_id();
|
||||
$structure = get_post_meta($page_id, '_wn_page_structure', true);
|
||||
|
||||
|
||||
if (!empty($structure) && !empty($structure['sections'])) {
|
||||
self::serve_ssr_content($page_id, 'page');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check for CPT items with templates
|
||||
$post_type = get_post_type();
|
||||
if ($post_type && is_singular() && $post_type !== 'page') {
|
||||
$template = get_option("wn_template_{$post_type}", null);
|
||||
|
||||
|
||||
if (!empty($template) && !empty($template['sections'])) {
|
||||
$post_obj = get_queried_object();
|
||||
self::serve_ssr_content($post_obj->ID, $post_type, $post_obj);
|
||||
@@ -946,4 +1032,3 @@ class TemplateOverride
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user