本文详解如何在 woocommerce 站点中全局拦截未登录用户访问(包括 /shop、/product、/my-account 等所有前台页面),并安全重定向至登录页,同时确保 rest api 及后台功能不受影响。
在 WooCommerce 项目中,若需实现“仅限登录用户访问全站前台内容”的策略(即未登录者一律跳转至登录页),不能依赖 is_page() 判断特定页面 ID 或 slug——因为 WooCommerce 的商品目录(如 /shop)、单个商品页(如 /product/xxx)、结账页等均由动态路由(rewrite rules)驱动,并非真实存在的 WordPress 页面,因此 is_page('shop') 始终返回 false,导致原始代码失效。
正确的做法是:在 template_redirect 钩子中,结合 $wp->request 获取当前请求的解析后路径(即重写后的 URL 路径),并排除登录、密码找回等关键入口,再执行重定向。以下是经过验证的健壮实现:
add_action('template_redirect', 'woo_force_login_redirect');
function woo_force_login_redirect() {
// 排除后台、REST API、XML-RPC、健康检查等系统请求
if (is_admin() || defined('WP_CLI') || wp_doing_ajax() || wp_doing_cron()) {
return;
}
global $wp;
// 获取当前请求路径(如 'shop', 'product/my-product', 'my-account/lost-password')
$current_request = trim($wp->request, '/');
// 允许访问的白名单路径(可按需扩展)
$allowed_paths = [
'wp-login.php',
'wp-register.php',
'my-account',
'my-account/lost-password',
'my-account/reset-password',
'my-account/edit-account',
'my-account/customer-logout'
];
// 检查是否已登录,且当前请求不在白名单中
if (!is_user_logged_in() && !in_array($current_request, $allowed_paths)) {
// 使用 wp_login_url() 生成带回跳参数的安全登录链接
$redirect_url = wp_login_url(esc_url_raw(add_query_arg([], home_url($wp->request))));
wp_safe_redirect($redirect_url);
exit;
}
}✅ 关键优势说明:
⚠️ 注意事项:
清晰提示(如:“请先登录以浏览商品”),提升 UX。此方案已在 WooCommerce 6.1+ 及 WordPress 6.0+ 环境实测通过,兼顾安全性、兼容性与可维护性,是生产环境推荐的标准实践。