
本文详解如何在 WordPress 自定义维护模式插件中,安全、可靠地排除指定页面(如登录页、调研页等)不显示维护页面,重点解决 is_page() 在早期钩子中不可用的问题及正确挂载时机。
本文详解如何在 wordpress 自定义维护模式插件中,安全、可靠地排除指定页面(如登录页、调研页等)不显示维护页面,重点解决 `is_page()` 在早期钩子中不可用的问题及正确挂载时机。
在 WordPress 开发中,为网站启用临时维护模式是常见需求,但必须确保关键页面(如 /wp-login.php、用户注册页、邮件订阅页、问卷调查页等)仍可正常访问。原始代码使用 wp_loaded 钩子配合 is_admin() 和 $pagenow 判断,虽能排除后台和登录页,却无法直接使用 is_page()——因为此时 WordPress 主题与全局查询($wp_query)尚未完全初始化,is_page() 等条件标签尚不可用,强行调用将始终返回 false。
✅ 正确解法:分层判断 + 延迟挂载
核心思路是:
- 先用早期可用的变量(如 $pagenow、$_SERVER['REQUEST_URI'])快速排除明确路径(如 wp-login.php);
- 对需依赖 is_page() 的页面(如自定义页面 survey),改用 template_redirect 或 wp 钩子——此时主查询已就绪,is_page() 完全可用;
- 避免在 wp_loaded 中直接调用 is_page(),而是重构逻辑,在合适时机执行维护拦截。
以下是推荐的优化实现:
function ng_maintenance_mode() {
// 1. 快速排除:登录页、后台、管理员用户(早期即可判断)
global $pagenow;
if ( $pagenow === 'wp-login.php' || is_admin() || current_user_can( 'manage_options' ) ) {
return;
}
// 2. 检查是否为需豁免的前端页面(如 slug 为 'survey' 的页面)
// 注意:此处必须在 wp 或 template_redirect 钩子中运行,确保 is_page() 可用
if ( is_page( 'survey' ) || is_page( 'opt-in' ) || is_page( 'thank-you' ) ) {
return;
}
// 3. 触发维护响应头并加载维护页
status_header(503);
header('Content-Type: text/html; charset=utf-8');
$maintenance_file = plugin_dir_path(__FILE__) . 'views/maintenance.php';
if (file_exists($maintenance_file)) {
require_once $maintenance_file;
}
exit;
}
// 关键:挂载到 wp 钩子(而非 wp_loaded),确保主查询已初始化
add_action('wp', 'ng_maintenance_mode');
? 重要注意事项:
- ❌ 不要将 is_page() 放在 wp_loaded 回调内——该钩子触发时 $wp_query 尚未设置,is_page() 必然失效;
- ✅ wp 钩子在 WP::main() 执行后、模板加载前触发,此时所有条件标签(is_page()、is_home()、is_singular() 等)均已可靠可用;
- ? 若需排除多个页面,建议使用数组形式提升可维护性:
$excluded_pages = ['survey', 'opt-in', 'contact', 'privacy-policy']; if (is_page() && in_array(get_queried_object()->post_name, $excluded_pages)) { return; } - ⚠️ 避免在维护逻辑中调用 die() 或裸 exit,优先使用 exit 并配合 status_header(),更符合 WordPress 响应规范;
- ? 测试时请在无缓存环境(或隐身窗口)下验证,避免浏览器/CDN 缓存干扰 503 响应。
总结:WordPress 维护模式的页面豁免不是简单的逻辑取反,而是对 WordPress 请求生命周期的精准把握。通过将判断逻辑迁移至 wp 钩子,并合理组合原生条件函数,即可灵活、健壮地实现任意页面的白名单机制,兼顾安全性与用户体验。











