First Version - Local CDN
This commit is contained in:
parent
3dcd7dbe84
commit
8b60581798
1
assets/select2/select2.min.css
vendored
Normal file
1
assets/select2/select2.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
2
assets/select2/select2.min.js
vendored
Normal file
2
assets/select2/select2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
166
maintenance-admin-style.css
Normal file
166
maintenance-admin-style.css
Normal file
@ -0,0 +1,166 @@
|
||||
/* ============ Maintenance Mode - Admin CSS ============ */
|
||||
|
||||
/* ============ Global Wrapper ============ */
|
||||
.maintenance-wrap {
|
||||
max-width: 100%;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
/* ============ Section Card ============ */
|
||||
.maintenance-card {
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
padding: 24px;
|
||||
margin-bottom: 24px;
|
||||
border-radius: 24px;
|
||||
}
|
||||
|
||||
/* ============ Field Block ============ */
|
||||
.maintenance-field {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.maintenance-field label {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
/* ============ Save Button ============ */
|
||||
button.button-primary {
|
||||
background: #0073aa;
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
padding: 8px 24px;
|
||||
font-size: 14px;
|
||||
border-radius: 8px;
|
||||
box-shadow: none;
|
||||
}
|
||||
button.button-primary:hover {
|
||||
background: #005e8a;
|
||||
}
|
||||
|
||||
/* ============ Tabs ============ */
|
||||
.acf-tabs {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.acf-tab {
|
||||
background: #e9e9e9;
|
||||
padding: 8px 16px;
|
||||
border-radius: 8px 8px 0 0;
|
||||
text-decoration: none;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.acf-tab-active {
|
||||
background: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border-bottom: none;
|
||||
padding: 9px 16px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.acf-tab:focus {
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
/* ============ Toggle Switch ============ */
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
height: 24px;
|
||||
}
|
||||
.switch input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
transition: .4s;
|
||||
border-radius: 24px;
|
||||
}
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
background-color: white;
|
||||
transition: .4s;
|
||||
border-radius: 50%;
|
||||
}
|
||||
input:checked + .slider {
|
||||
background-color: #0073aa;
|
||||
}
|
||||
input:checked + .slider:before {
|
||||
transform: translateX(22px);
|
||||
}
|
||||
|
||||
/* ============ Admin Bar Maintenance Label ============ */
|
||||
#wp-admin-bar-maintenance_mode_status .ab-item.maintenance-on {
|
||||
background: #46b450;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
#wp-admin-bar-maintenance_mode_status .ab-item.maintenance-off {
|
||||
background: transparent;
|
||||
color: #bbb;
|
||||
font-weight: bold;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* ============ Flex Row Between for Header Label + Toggle ============ */
|
||||
.flex-row-between {
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
align-items: center;
|
||||
}
|
||||
.flex-row-between label {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
/* ============ Form Select2 Custom ============ */
|
||||
.select2-container--default .select2-selection--multiple {
|
||||
border-radius: 6px;
|
||||
border-color: #ddd;
|
||||
min-height: 38px;
|
||||
}
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice {
|
||||
background: #f3f3f3;
|
||||
border: none;
|
||||
color: #333;
|
||||
font-size: 13px;
|
||||
border-radius: 4px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.select2-container--default .select2-selection--multiple:focus,
|
||||
.select2-container--default .select2-selection--single:focus {
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
border-color: #0073aa;
|
||||
}
|
||||
|
||||
/* ============ Remove Focus Ring on Mouse Hold ============ */
|
||||
.acf-tab:focus-visible,
|
||||
.acf-tab:focus {
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
212
maintenance-von-moh.php
Normal file
212
maintenance-von-moh.php
Normal file
@ -0,0 +1,212 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: Maintenance von Moh
|
||||
* Description: Custom maintenance mode with page exclusion, roles control, IP whitelist, and more.
|
||||
* Version: 2.1
|
||||
* Author: Moh Farawati
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
class Moh_Maintenance_Mode {
|
||||
private $options;
|
||||
|
||||
public function __construct() {
|
||||
$defaults = [
|
||||
'enable_maintenance' => false,
|
||||
'excluded_slugs' => [],
|
||||
'excluded_ips' => [],
|
||||
'excluded_roles' => [],
|
||||
'redirect_url' => '/maintenance'
|
||||
];
|
||||
$saved_options = get_option('ab_maintenance_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('admin_enqueue_scripts', [$this, 'enqueue_admin_assets']);
|
||||
add_action('template_redirect', [$this, 'handle_redirect']);
|
||||
add_action('admin_notices', [$this, 'admin_notice']);
|
||||
add_action('admin_bar_menu', [$this, 'add_admin_bar_status'], 100);
|
||||
}
|
||||
|
||||
public function admin_menu() {
|
||||
add_menu_page(
|
||||
'Maintenance von Moh',
|
||||
'Maintenance Mode',
|
||||
'manage_options',
|
||||
'ab_maintenance',
|
||||
[$this, 'settings_page'],
|
||||
'dashicons-shield',
|
||||
80
|
||||
);
|
||||
}
|
||||
|
||||
public function enqueue_admin_assets() {
|
||||
if (isset($_GET['page']) && $_GET['page'] === 'ab_maintenance') {
|
||||
wp_enqueue_style('maintenance-admin-style', plugin_dir_url(__FILE__) . 'maintenance-admin-style.css', [], filemtime(plugin_dir_path(__FILE__) . 'maintenance-admin-style.css'));
|
||||
wp_enqueue_script('select2', plugin_dir_url(__FILE__) . 'assets/select2/select2.min.js', ['jquery'], '4.1.0', true);
|
||||
wp_enqueue_style('select2-style', plugin_dir_url(__FILE__) . 'assets/select2/select2.min.css', [], '4.1.0');
|
||||
add_action('admin_footer', function () {
|
||||
echo "<script>jQuery(document).ready(function($){ $('.acf-style-select').select2(); $('.nav-tab').on('mousedown', function(e){ e.preventDefault(); }); });</script>";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public function register_settings() {
|
||||
register_setting('ab_maintenance_group', 'ab_maintenance_settings', [
|
||||
'sanitize_callback' => [$this, 'sanitize_settings']
|
||||
]);
|
||||
}
|
||||
|
||||
public function sanitize_settings($input) {
|
||||
add_option('ab_maintenance_settings_saved', 1);
|
||||
return [
|
||||
'enable_maintenance' => isset($input['enable_maintenance']) ? true : false,
|
||||
'excluded_slugs' => isset($input['excluded_slugs']) ? array_filter(array_map('sanitize_title', (array) $input['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')
|
||||
];
|
||||
}
|
||||
|
||||
public function admin_notice() {
|
||||
if (get_option('ab_maintenance_settings_saved')) {
|
||||
delete_option('ab_maintenance_settings_saved');
|
||||
echo '<div class="notice notice-success is-dismissible"><p>Settings saved successfully.</p></div>';
|
||||
}
|
||||
}
|
||||
|
||||
public function add_admin_bar_status($wp_admin_bar) {
|
||||
if (!current_user_can('manage_options')) return;
|
||||
$enabled = !empty($this->options['enable_maintenance']);
|
||||
$label = $enabled ? 'Maintenance: ON' : 'Maintenance: OFF';
|
||||
$class = $enabled ? 'ab-item maintenance-on' : 'ab-item maintenance-off';
|
||||
$wp_admin_bar->add_node([
|
||||
'id' => 'maintenance_mode_status',
|
||||
'title' => '<span class="' . esc_attr($class) . '">' . esc_html($label) . '</span>',
|
||||
'href' => admin_url('admin.php?page=ab_maintenance')
|
||||
]);
|
||||
}
|
||||
|
||||
public function settings_page() {
|
||||
$active_tab = isset($_GET['tab']) ? sanitize_text_field($_GET['tab']) : 'general';
|
||||
$settings = wp_parse_args(get_option('ab_maintenance_settings', []), $this->options);
|
||||
$settings['excluded_slugs'] = is_array($settings['excluded_slugs']) ? $settings['excluded_slugs'] : [];
|
||||
$settings['excluded_ips'] = is_array($settings['excluded_ips']) ? $settings['excluded_ips'] : [];
|
||||
$settings['excluded_roles'] = is_array($settings['excluded_roles']) ? $settings['excluded_roles'] : [];
|
||||
?>
|
||||
<div class="wrap maintenance-wrap">
|
||||
<h1>🛡️ Maintenance Mode</h1>
|
||||
|
||||
<div class="acf-tabs">
|
||||
<a href="?page=ab_maintenance&tab=general" class="acf-tab <?php echo $active_tab == 'general' ? 'acf-tab-active' : ''; ?>">General</a>
|
||||
<a href="?page=ab_maintenance&tab=advanced" class="acf-tab <?php echo $active_tab == 'advanced' ? 'acf-tab-active' : ''; ?>">Advanced</a>
|
||||
<a href="?page=ab_maintenance&tab=about" class="acf-tab <?php echo $active_tab == 'about' ? 'acf-tab-active' : ''; ?>">About</a>
|
||||
</div>
|
||||
|
||||
<?php if ($active_tab == 'general') : ?>
|
||||
<form method="post" action="options.php">
|
||||
<?php settings_fields('ab_maintenance_group'); ?>
|
||||
|
||||
<div class="maintenance-card">
|
||||
<div class="maintenance-field flex-row-between">
|
||||
<label><strong>Enable Maintenance Mode</strong></label>
|
||||
<label class="switch">
|
||||
<input type="checkbox" name="ab_maintenance_settings[enable_maintenance]" value="1" <?php checked($settings['enable_maintenance'], true); ?> />
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="maintenance-card">
|
||||
<div class="maintenance-field">
|
||||
<label><strong>Excluded Pages</strong></label>
|
||||
<select name="ab_maintenance_settings[excluded_slugs][]" multiple class="acf-style-select" style="width:100%">
|
||||
<?php foreach (get_pages() as $page) : $slug = basename(get_permalink($page->ID)); ?>
|
||||
<option value="<?php echo $slug; ?>" <?php selected(in_array($slug, $settings['excluded_slugs'])); ?>><?php echo esc_html($page->post_title); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<p class="description">Select pages to exclude from maintenance. You can select multiple.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="maintenance-card">
|
||||
<div class="maintenance-field">
|
||||
<label><strong>Excluded IPs</strong></label>
|
||||
<input type="text" name="ab_maintenance_settings[excluded_ips]" value="<?php echo esc_attr(implode(',', $settings['excluded_ips'])); ?>" class="regular-text" />
|
||||
<p class="description">Example: <code>127.0.0.1,88.21.33.77</code></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="maintenance-card">
|
||||
<div class="maintenance-field">
|
||||
<label><strong>Excluded Roles</strong></label>
|
||||
<select name="ab_maintenance_settings[excluded_roles][]" multiple class="acf-style-select" style="width:100%">
|
||||
<?php global $wp_roles; foreach ($wp_roles->roles as $key => $role) : ?>
|
||||
<option value="<?php echo esc_attr($key); ?>" <?php selected(in_array($key, $settings['excluded_roles'])); ?>><?php echo esc_html($role['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<p class="description">Select user roles that should bypass maintenance mode.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="maintenance-card">
|
||||
<div class="maintenance-field">
|
||||
<label><strong>Redirect Page</strong></label>
|
||||
<select name="ab_maintenance_settings[redirect_url]" class="acf-style-select" style="width:100%">
|
||||
<?php foreach (get_pages() as $page) : $slug = '/' . basename(get_permalink($page->ID)); ?>
|
||||
<option value="<?php echo esc_attr($slug); ?>" <?php selected($settings['redirect_url'], $slug); ?>><?php echo esc_html($page->post_title); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<p class="description">Choose the page visitors will be redirected to.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="maintenance-card">
|
||||
<button type="submit" class="button button-primary" style="border-radius:6px;padding:8px 22px;font-size:14px;">Save Settings</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<?php elseif ($active_tab == 'advanced') : ?>
|
||||
<p>🚧 Coming soon: advanced tools and features.</p>
|
||||
|
||||
<?php elseif ($active_tab == 'about') : ?>
|
||||
<p><strong>Maintenance</strong> by Moh Farawati.<br>This plugin was crafted with ❤️ to help developers manage maintenance with control and elegance.</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function handle_redirect() {
|
||||
if (empty($this->options['enable_maintenance'])) return;
|
||||
|
||||
if (is_user_logged_in()) {
|
||||
$user = wp_get_current_user();
|
||||
foreach ($user->roles as $role) {
|
||||
if (in_array($role, $this->options['excluded_roles'])) return;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array($_SERVER['REMOTE_ADDR'], $this->options['excluded_ips'])) return;
|
||||
|
||||
global $wp_query;
|
||||
if (!$this->options['enable_maintenance'] && $wp_query->is_404()) return;
|
||||
|
||||
$current_path = trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/');
|
||||
$redirect_path = trim($this->options['redirect_url'], '/');
|
||||
|
||||
if ($current_path === $redirect_path) return;
|
||||
|
||||
foreach ($this->options['excluded_slugs'] as $slug) {
|
||||
if (stripos($current_path, $slug) !== false) return;
|
||||
}
|
||||
|
||||
if (!is_admin()) {
|
||||
wp_redirect(home_url($this->options['redirect_url']));
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new Moh_Maintenance_Mode();
|
||||
49
readme.txt
Normal file
49
readme.txt
Normal file
@ -0,0 +1,49 @@
|
||||
=== Maintenance von Moh ===
|
||||
Contributors: mohfarawati
|
||||
Tags: maintenance, under construction, coming soon, maintenance mode, restrict access
|
||||
Requires at least: 5.0
|
||||
Tested up to: 6.5
|
||||
Requires PHP: 7.2
|
||||
Stable tag: 1.4
|
||||
License: GPLv2 or later
|
||||
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
🛠️ A lightweight custom maintenance mode plugin with exclusions for slugs, IPs, and roles. Built by Moh Farawati for developers and agencies.
|
||||
|
||||
== Description ==
|
||||
|
||||
**Maintenance von Moh** lets you activate maintenance mode and define:
|
||||
|
||||
- Slugs to exclude (e.g. `/qr`, `/telegram`)
|
||||
- Specific IPs that bypass maintenance mode
|
||||
- Roles that can access the site
|
||||
- Custom redirect URL for maintenance page
|
||||
|
||||
Perfect for agencies working on multiple client sites.
|
||||
|
||||
== Installation ==
|
||||
|
||||
1. Upload the plugin to `/wp-content/plugins/maintenance-von-moh/`
|
||||
2. Activate the plugin via the Plugins menu
|
||||
3. Navigate to "Maintenance Mode" in your admin panel
|
||||
|
||||
== Frequently Asked Questions ==
|
||||
|
||||
= Can I exclude specific pages? =
|
||||
Yes! Just enter their slugs in the field, comma-separated.
|
||||
|
||||
= Can I customize the redirect page? =
|
||||
Yes. Simply set the full relative URL (e.g. `/maintenance`).
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 1.4 =
|
||||
* UI enhancement
|
||||
* Plugin folder and file renamed
|
||||
* Full CSS support added
|
||||
|
||||
= 1.3 =
|
||||
* IP and role exclusion support
|
||||
|
||||
= 1.0 =
|
||||
* Initial release
|
||||
Loading…
x
Reference in New Issue
Block a user