false, 'excluded_slugs' => [], // e.g. ["qr", "coming-soon", "shop/qr"] 'excluded_ips' => [], 'excluded_roles' => [], 'allowed_users' => [], 'redirect_url' => '/maintenance', ]; $saved_options = get_option('pausera_settings', []); $this->options = wp_parse_args($saved_options, $defaults); add_action('admin_menu', [$this, 'admin_menu']); add_action('admin_init', [$this, 'register_settings']); add_action('template_redirect', [$this, 'handle_redirect']); add_action('admin_bar_menu', [$this, 'add_admin_bar_status'], 100); } /************************************************************************************ * settings registration + sanitization ************************************************************************************/ public function register_settings() { register_setting('pausera_group', 'pausera_settings', [ 'sanitize_callback' => [$this, 'sanitize_settings'] ]); } public function sanitize_settings($input) { add_option('pausera_settings_saved', 1); // Keep nested paths like "shop/qr" clean $sanitize_path = function ($val) { $val = is_string($val) ? trim($val) : ''; $val = trim($val, "/ \t\n\r\0\x0B"); if ($val === '') return ''; $parts = array_filter(explode('/', $val), 'strlen'); $parts = array_map('sanitize_title', $parts); return implode('/', $parts); }; $excluded_slugs = []; if (isset($input['excluded_slugs'])) { $raw = is_array($input['excluded_slugs']) ? $input['excluded_slugs'] : [$input['excluded_slugs']]; foreach ($raw as $r) { $s = $sanitize_path($r); if ($s !== '') $excluded_slugs[] = $s; } $excluded_slugs = array_values(array_unique($excluded_slugs)); } return [ 'enable_maintenance' => !empty($input['enable_maintenance']), 'excluded_slugs' => $excluded_slugs, 'excluded_ips' => array_filter(array_map('trim', explode(',', sanitize_text_field($input['excluded_ips'] ?? '')))), 'excluded_roles' => isset($input['excluded_roles']) ? array_filter(array_map('sanitize_text_field', (array) $input['excluded_roles'])) : [], 'redirect_url' => esc_url_raw($input['redirect_url'] ?? '/maintenance'), 'allowed_users' => isset($input['allowed_users']) ? array_filter(array_map('sanitize_user', (array) $input['allowed_users'])) : [], ]; } /************************************************************************************ * admin UI + notices ************************************************************************************/ public function admin_menu() { add_menu_page( 'Pausera', 'Pausera', 'manage_options', 'pausera', [$this, 'settings_page'], 'dashicons-shield-alt', 80 ); } public function settings_page() { do_action('pausera_render_ui'); } public function add_admin_bar_status($wp_admin_bar) { if (!current_user_can('manage_options')) return; $enabled = !empty($this->options['enable_maintenance']); $label = 'Pausera: ' . ($enabled ? 'ON' : 'OFF'); $color = $enabled ? 'orange' : '#999'; $wp_admin_bar->add_node([ 'id' => 'pausera_status', 'title' => '' . esc_html($label) . '', 'href' => admin_url('admin.php?page=pausera'), 'meta' => ['title' => 'Pausera Status'] ]); } /************************************************************************************ * redirect logic ************************************************************************************/ private function path_matches($current_path, $slug) { $slug = trim($slug, "/ \t\n\r\0\x0B"); if ($slug === '') return false; if ($current_path === $slug) return true; // exact if (strpos($current_path, $slug . '/') === 0) return true; // prefix segment return false; } private function is_public_system_request($current_path) { if (function_exists('wp_doing_ajax') && wp_doing_ajax()) return true; if (defined('REST_REQUEST') && REST_REQUEST) return true; if (strpos($current_path, 'wp-json') === 0) return true; $script = $_SERVER['SCRIPT_NAME'] ?? ''; if (strpos($script, 'wp-login.php') !== false) return true; if (strpos($script, 'wp-cron.php') !== false) return true; if (function_exists('is_customize_preview') && is_customize_preview()) return true; if (is_feed()) return true; return false; } public function handle_redirect() { if (empty($this->options['enable_maintenance'])) return; if (is_user_logged_in()) { $user = wp_get_current_user(); if (in_array($user->user_login, $this->options['allowed_users'] ?? [], true)) return; foreach ((array) $user->roles as $role) { if (in_array($role, (array) $this->options['excluded_roles'], true)) return; } } $remote_ip = $_SERVER['REMOTE_ADDR'] ?? ''; if ($remote_ip && in_array($remote_ip, (array) $this->options['excluded_ips'], true)) return; $current_path = trim(parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?? '', '/'); $redirect_path = trim($this->options['redirect_url'] ?? '/maintenance', '/'); if ($this->is_public_system_request($current_path)) return; if ($current_path === $redirect_path) return; foreach ((array) $this->options['excluded_slugs'] as $slug) { if ($this->path_matches($current_path, $slug)) return; } if (!is_admin()) { wp_safe_redirect(home_url('/' . ltrim($redirect_path, '/'))); exit; } } } /************************************************************************************ * bootstrap ************************************************************************************/ add_action('plugins_loaded', function () { $GLOBALS['pausera_instance'] = new Pausera(); });