pausera/pausera.php

195 lines
6.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/************************************************************************************
* Pausera Lightweight maintenance mode with role/user/IP/page exclusions
************************************************************************************/
/*
Plugin Name: Pausera
Description: Maintenance mode with exclusions (roles, users, IPs, specific pages) and a simple admin UI.
Version: 1.0.1-hotfix
Author: Your Name
*/
if (!defined('ABSPATH')) exit;
if (!defined('PAUSERA_PATH')) define('PAUSERA_PATH', plugin_dir_path(__FILE__));
if (!defined('PAUSERA_URL')) define('PAUSERA_URL', plugin_dir_url(__FILE__));
require_once PAUSERA_PATH . 'includes/assets.php';
require_once PAUSERA_PATH . 'includes/admin-ui.php';
class Pausera
{
private $options;
/************************************************************************************
* constructor
************************************************************************************/
public function __construct()
{
$defaults = [
'enable_maintenance' => 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' => '<span style="color:' . esc_attr($color) . '; font-weight: bold;">' . esc_html($label) . '</span>',
'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();
});