Plugin Directory

Changeset 3491444


Ignore:
Timestamp:
03/26/2026 05:31:53 AM (2 days ago)
Author:
robustdecoders
Message:

Updated plugin to version 2.0.0

Location:
dynamic-maintenance-mode/trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • dynamic-maintenance-mode/trunk/dynamic-maintenance-mode.php

    r3485289 r3491444  
    33 * Plugin Name: Dynamic Maintenance Mode
    44 * Description:  Enable maintenance mode with custom page, user scope and scheduling.
    5  * Version: 1.1.1
     5 * Version: 2.0.0
    66 * License: GPLv2 or later
    77 * Author: robustdecoders
  • dynamic-maintenance-mode/trunk/includes/functions.php

    r3485289 r3491444  
    11<?php
    22defined('ABSPATH') || exit;
    3 
     3ob_start();
     4
     5function dmmrd_is_frontend_request() {
     6    if (is_admin()) {
     7        return false;
     8    }
     9
     10    if (function_exists('wp_doing_ajax') && wp_doing_ajax()) {
     11        return false;
     12    }
     13
     14    if (defined('REST_REQUEST') && REST_REQUEST) {
     15        return false;
     16    }
     17
     18    if (defined('DOING_CRON') && DOING_CRON) {
     19        return false;
     20    }
     21
     22    if (defined('WP_CLI') && WP_CLI) {
     23        return false;
     24    }
     25
     26    return true;
     27}
     28
     29function dmmrd_clear_all_output_buffers() {
     30    while (ob_get_level() > 0) {
     31        @ob_end_clean();
     32    }
     33}
     34
     35function dmmrd_error_type_label($errno) {
     36    switch ((int) $errno) {
     37        case E_ERROR:
     38        case E_USER_ERROR:
     39            return 'Error';
     40        case E_WARNING:
     41        case E_USER_WARNING:
     42            return 'Warning';
     43        case E_NOTICE:
     44        case E_USER_NOTICE:
     45            return 'Notice';
     46        case E_DEPRECATED:
     47        case E_USER_DEPRECATED:
     48            return 'Deprecated';
     49        case E_PARSE:
     50            return 'Parse Error';
     51        case E_CORE_ERROR:
     52            return 'Core Error';
     53        case E_COMPILE_ERROR:
     54            return 'Compile Error';
     55        case E_RECOVERABLE_ERROR:
     56            return 'Recoverable Error';
     57        default:
     58            return 'PHP Error';
     59    }
     60}
     61
     62function dmmrd_render_emergency_maintenance_page() {
     63    $message = get_option('dmmrd_custom_message');
     64    $image = get_option('dmmrd_custom_image');
     65    $custom_enabled = (bool) get_option('dmmrd_enable_custom_msg');
     66
     67    if (!$custom_enabled || !$message) {
     68        $message = '<h1>Site Under Maintenance</h1><p>We are temporarily unavailable. Please check back shortly.</p>';
     69    }
     70
     71    echo '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Maintenance</title>';
     72    echo '<style>body{font-family:"Segoe UI",Arial,sans-serif;text-align:center;padding-top:120px;background:#f9f9f9;color:#333;margin:0}.container{max-width:680px;margin:0 auto;padding:20px}.dmmrd-content{font-size:18px;color:#555;line-height:1.7}.dmmrd-content h1,.dmmrd-content h2,.dmmrd-content h3{color:#2c3e50;margin-bottom:15px}.dmmrd-content p{margin-bottom:15px}.dmmrd-content img{max-width:100%;height:auto;border-radius:8px;margin:15px 0}</style>';
     73    echo '</head><body><div class="container">';
     74
     75    if ($image) {
     76        echo '<img src="' . esc_url($image) . '" alt="Maintenance">';
     77    } else {
     78        echo '<div style="font-size:60px;">&#128736;&#65039;</div>';
     79    }
     80
     81    echo '<div class="dmmrd-content">' . wp_kses_post(wpautop($message)) . '</div>';
     82    echo '</div></body></html>';
     83}
     84
     85function dmmrd_trigger_emergency_maintenance($source, $details) {
     86    static $rendering = false;
     87
     88    if ($rendering) {
     89        return;
     90    }
     91
     92    if (!dmmrd_is_frontend_request()) {
     93        return;
     94    }
     95
     96    if (!get_option('dmmrd_auto_maintenance_on_error')) {
     97        return;
     98    }
     99
     100    $rendering = true;
     101
     102    dmmrd_add_log(sprintf('%s: %s', $source, $details), 'Runtime', 'N/A');
     103    update_option('dmmrd_enable_mode', 1);
     104
     105    dmmrd_clear_all_output_buffers();
     106
     107    if (!headers_sent()) {
     108        status_header(503);
     109        nocache_headers();
     110        header('Content-Type: text/html; charset=' . get_bloginfo('charset'));
     111    }
     112
     113    if (function_exists('dmmrd_show_maintenance_notice')) {
     114        dmmrd_show_maintenance_notice();
     115    }
     116
     117    dmmrd_render_emergency_maintenance_page();
     118    exit;
     119}
    4120function dmmrd_handle_maintenance_mode()
    5121{
    6     if (!get_option('dmmrd_enable_mode')) return;
     122    if (!dmmrd_is_frontend_request()) {
     123        return;
     124    }
     125
     126    $repeat_enabled = (bool) get_option('dmmrd_repeat_enable');
     127    $repeat_active  = false;
     128
     129    if ($repeat_enabled) {
     130        $repeat_active = dmmrd_is_recurring_active();
     131        dmmrd_maybe_log_recurring_state($repeat_active);
     132    }
     133
     134    $manual_enabled = (bool) get_option('dmmrd_enable_mode');
     135    if (!$manual_enabled && !$repeat_active) {
     136        return;
     137    }
    7138
    8139    $scope = get_option('dmmrd_mode_scope', 'all');
     
    44175    $now_ts = (new DateTime('now', new DateTimeZone('Asia/Kolkata')))->getTimestamp();
    45176
    46     if ($type === 'alltime') {
     177   if ($type === 'alltime') {
     178    if ($repeat_enabled && !$repeat_active) {
     179        return;
     180    }
     181
     182    if (!$repeat_enabled) {
    47183        dmmrd_add_log(
    48184            'Always ON Maintenance activated',
    49             'N/A',
    50             'Until Disabled'
     185            'N/A',
     186            'Until Disabled'
     187        );
     188    }
     189
     190    dmmrd_show_maintenance_notice();
     191
     192} elseif ($type === 'schedule') {
     193
     194    $start_time_str = get_option('dmmrd_start_time');
     195    $end_time_str   = get_option('dmmrd_end_time');
     196
     197if ($repeat_enabled) {
     198    if (!$repeat_active) {
     199        return;
     200    }
     201
     202    dmmrd_show_maintenance_notice();
     203    return;
     204}
     205
     206    if (!$start_time_str || !$end_time_str) return;
     207
     208    $start = dmmrd_get_timestamp_from_indian_datetime($start_time_str);
     209    $end   = dmmrd_get_timestamp_from_indian_datetime($end_time_str);
     210
     211    if ($start && $end && $now_ts >= $start && $now_ts <= $end) {
     212        dmmrd_add_log(
     213            'Scheduled Maintenance activated',
     214            $start_time_str,
     215            $end_time_str
    51216        );
    52217        dmmrd_show_maintenance_notice();
    53        
    54     } elseif ($type === 'schedule') {
    55         $start_time_str = get_option('dmmrd_start_time');
    56         $end_time_str   = get_option('dmmrd_end_time');
    57        
    58         if (!$start_time_str || !$end_time_str) return;
    59 
    60         $start = dmmrd_get_timestamp_from_indian_datetime($start_time_str);
    61         $end   = dmmrd_get_timestamp_from_indian_datetime($end_time_str);
    62 
    63         if ($start && $end && $now_ts >= $start && $now_ts <= $end) {
    64             dmmrd_add_log(
    65                 'Scheduled Maintenance activated',
    66                 $start_time_str,
    67                 $end_time_str
    68             );
    69             dmmrd_show_maintenance_notice();
    70         }
     218    }
    71219    }
    72220}
     
    86234function dmmrd_show_maintenance_notice() {
    87235
    88     status_header(503);
    89 
    90     echo '<!DOCTYPE html>
    91     <html lang="en">
    92     <head>
    93         <meta charset="UTF-8">
    94         <meta name="viewport" content="width=device-width, initial-scale=1.0">
    95         <title>Site Under Maintenance</title>
    96         <style>
    97             body {
    98                 font-family: "Segoe UI", Arial, sans-serif;
    99                 text-align: center;
    100                 padding-top: 150px;
    101                 background-color: #f9f9f9;
    102                 color: #333;
    103                 margin: 0;
    104             }
    105             .container {
    106                 max-width: 600px;
    107                 margin: 0 auto;
    108                 padding: 20px;
    109             }
    110             h1 {
    111                 font-size: 40px;
    112                 margin-bottom: 20px;
    113                 color: #2c3e50;
    114             }
    115             p {
    116                 font-size: 20px;
    117                 color: #7f8c8d;
    118                 line-height: 1.6;
    119             }
    120             .icon {
    121                 font-size: 60px;
    122                 margin-bottom: 20px;
    123                 display: block;
    124             }
    125         </style>
    126     </head>
    127     <body>
    128         <div class="container">
    129             <span class="icon">🛠️</span>
    130             <h1>Site Under Maintenance</h1>
    131             <p>We are currently performing scheduled maintenance.<br>Please check back with us shortly.</p>
    132         </div>
    133     </body>
    134     </html>';
    135 
    136     exit;
    137 }
    138 
    139 
     236    if (!dmmrd_is_frontend_request()) {
     237        return;
     238    }
     239
     240    if (!headers_sent()) {
     241        status_header(503);
     242        nocache_headers();
     243        header('Content-Type: text/html; charset=' . get_bloginfo('charset'));
     244    }
     245
     246    $custom_page_enabled = (bool) get_option('dmmrd_enable_custom_page');
     247    $page_id = absint(get_option('dmmrd_custom_display_page'));
     248
     249    if ($custom_page_enabled && $page_id && (!function_exists('is_page') || !is_page($page_id))) {
     250        $page = get_post($page_id);
     251        if ($page instanceof WP_Post) {
     252            // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
     253            $page_content = apply_filters('the_content', (string) $page->post_content);
     254            dmmrd_output_maintenance_markup((string) $page_content, '');
     255            exit;
     256        }
     257    }
     258
     259    $custom_enabled = (bool) get_option('dmmrd_enable_custom_msg');
     260    $image = esc_url(get_option('dmmrd_custom_image'));
     261
     262    $default_message = '<h1>Site Under Maintenance</h1><p>We are currently performing scheduled maintenance.<br>Please check back shortly.</p>';
     263
     264    $raw_message = (string) get_option('dmmrd_custom_message', '');
     265    $safe_message = wp_kses_post($raw_message);
     266
     267    $content_html = $custom_enabled
     268        ? wp_kses_post(wpautop($safe_message ?: $default_message))
     269        : wp_kses_post(wpautop($default_message));
     270
     271
     272    dmmrd_output_maintenance_markup($content_html, $image);
     273    exit;
     274}
     275
     276function dmmrd_output_maintenance_markup($content_html, $image_url = '') {
     277    echo '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Maintenance</title>';
     278    echo '<style>body{font-family:"Segoe UI",Arial,sans-serif;text-align:center;padding-top:120px;background:#f9f9f9;color:#333;margin:0}.container{max-width:680px;margin:0 auto;padding:20px}.dmmrd-content{font-size:18px;color:#555;line-height:1.7}.dmmrd-content h1,.dmmrd-content h2,.dmmrd-content h3{color:#2c3e50;margin-bottom:15px}.dmmrd-content p{margin-bottom:15px}.dmmrd-image{max-width:100%;height:auto;border-radius:8px;margin:15px 0}.icon{font-size:60px;display:inline-block;margin:10px 0 20px}</style>';
     279    echo '</head><body><div class="container">';
     280
     281    if (!empty($image_url)) {
     282        echo '<img class="dmmrd-image" src="' . esc_url($image_url) . '" alt="Maintenance">';
     283    } else {
     284        echo '<span class="icon">&#128736;&#65039;</span>';
     285    }
     286
     287    echo '<div class="dmmrd-content">' . wp_kses_post((string) $content_html) . '</div>';
     288    echo '</div></body></html>';
     289}
    140290add_action('wp', 'dmmrd_show_shop_page_notice');
    141291function dmmrd_show_shop_page_notice()
     
    200350
    201351function dmmrd_enable_error_logging() {
    202     // Check karein setting ON hai ya nahi
    203     if ( ! get_option('dmmrd_advanced_mode') ) {
    204         return;
    205     }
    206 
    207     /**
    208      * 1. PHP Error Handler (Warnings/Notices)
    209      * phpcs:ignore ignore comment scanner ko bypass karne ke liye
    210      */
    211     // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler
    212     set_error_handler( function( $errno, $errstr, $errfile, $errline ) {
    213        
    214         // phpcs:ignore WordPress.PHP.DevelopmentFunctions.prevent_path_disclosure_error_reporting
    215         $current_reporting = error_reporting();
    216        
    217         if ( 0 === $current_reporting || ! ( $current_reporting & $errno ) ) {
     352    if (!dmmrd_is_frontend_request()) {
     353        return;
     354    }
     355
     356    $logging_enabled = (bool) get_option('dmmrd_advanced_mode');
     357    $auto_maintenance_enabled = (bool) get_option('dmmrd_auto_maintenance_on_error');
     358
     359    if (!$logging_enabled && !$auto_maintenance_enabled) {
     360        return;
     361    }
     362// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler
     363    set_error_handler(function ($errno, $errstr, $errfile, $errline) use ($logging_enabled, $auto_maintenance_enabled) {
     364        static $handling_error = false;
     365
     366        if ($handling_error) {
    218367            return false;
    219368        }
    220 
    221         $type = 'PHP Error';
    222         switch ( $errno ) {
    223             case E_WARNING: case E_USER_WARNING: $type = 'Warning'; break;
    224             case E_NOTICE:  case E_USER_NOTICE:  $type = 'Notice'; break;
    225             case E_DEPRECATED: $type = 'Deprecated'; break;
    226         }
    227 
    228         // basename() use kiya hai taaki Full Path leak na ho (Security)
    229         $message = sprintf( '%s: %s in %s line %d', $type, $errstr, basename( $errfile ), $errline );
    230        
    231         if ( function_exists( 'dmmrd_add_log' ) ) {
    232             dmmrd_add_log( $message, 'Runtime', 'N/A' );
    233         }
    234         return false;
    235     } );
    236 
    237     /**
    238      * 2. Exception Handler (Uncaught Exceptions)
    239      */
    240     set_exception_handler( function( $exception ) {
    241         $message = sprintf(
    242             'Exception: %s in %s line %d',
    243             $exception->getMessage(),
    244             basename( $exception->getFile() ),
    245             $exception->getLine()
     369// phpcs:ignore WordPress.PHP.DevelopmentFunctions.prevent_path_disclosure_error_reporting
     370        $current_reporting = error_reporting();
     371        if (0 === $current_reporting || !($current_reporting & $errno)) {
     372            return false;
     373        }
     374
     375        $handling_error = true;
     376
     377        $type = dmmrd_error_type_label($errno);
     378        $message = sprintf('%s: %s in %s line %d', $type, (string) $errstr, basename((string) $errfile), (int) $errline);
     379
     380        if ($logging_enabled) {
     381            dmmrd_add_log($message, 'Runtime', 'N/A');
     382        }
     383
     384        if ($auto_maintenance_enabled) {
     385            dmmrd_trigger_emergency_maintenance('Runtime Error', $message);
     386            return true;
     387        }
     388
     389        $handling_error = false;
     390        return false;
     391    });
     392
     393    set_exception_handler(function ($exception) use ($logging_enabled, $auto_maintenance_enabled) {
     394        static $handling_exception = false;
     395
     396        if ($handling_exception) {
     397            return;
     398        }
     399
     400        $handling_exception = true;
     401
     402        if ($exception instanceof Throwable) {
     403            $message = sprintf(
     404                'Exception: %s in %s line %d',
     405                $exception->getMessage(),
     406                basename($exception->getFile()),
     407                (int) $exception->getLine()
     408            );
     409        } else {
     410            $message = 'Exception: Unknown exception object received';
     411        }
     412
     413        dmmrd_add_log($message, 'Exception', 'N/A');
     414
     415        if ($auto_maintenance_enabled) {
     416            dmmrd_trigger_emergency_maintenance('Uncaught Exception', $message);
     417        }
     418    });
     419
     420    register_shutdown_function(function () use ($logging_enabled, $auto_maintenance_enabled) {
     421        $error = error_get_last();
     422
     423        if (!$error || !isset($error['type'])) {
     424            return;
     425        }
     426
     427        $fatal_types = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR];
     428        if (!in_array((int) $error['type'], $fatal_types, true)) {
     429            return;
     430        }
     431
     432        $type = dmmrd_error_type_label((int) $error['type']);
     433        $message = sprintf(
     434            '%s: %s in %s line %d',
     435            $type,
     436            isset($error['message']) ? (string) $error['message'] : 'Unknown fatal error',
     437            isset($error['file']) ? basename((string) $error['file']) : 'unknown file',
     438            isset($error['line']) ? (int) $error['line'] : 0
    246439        );
    247        
    248         if ( function_exists( 'dmmrd_add_log' ) ) {
    249             dmmrd_add_log( $message, 'Exception', 'N/A' );
    250         }
    251     } );
    252 
    253     /**
    254      * 3. Shutdown Function (Fatal Errors / White Screen)
    255      */
    256     register_shutdown_function( function() {
    257         $error = error_get_last();
    258        
    259         // Sirf Critical errors ko filter karna
    260         if ( $error && in_array( $error['type'], array( E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR ), true ) ) {
    261             $message = sprintf(
    262                 'Fatal Error: %s in %s line %d',
    263                 $error['message'],
    264                 basename( $error['file'] ),
    265                 $error['line']
    266             );
    267            
    268             if ( function_exists( 'dmmrd_add_log' ) ) {
    269                 dmmrd_add_log( $message, 'Critical', 'N/A' );
    270             }
    271         }
    272     } );
    273 }
    274 
    275 function dmmrd_add_log($message, $start = 'N/A', $end = 'N/A') {
     440
     441        if ($logging_enabled) {
     442            dmmrd_add_log($message, 'Critical', 'N/A');
     443        }
     444
     445        if ($auto_maintenance_enabled) {
     446            dmmrd_trigger_emergency_maintenance('Fatal Error', $message);
     447        }
     448    });
     449}
     450
     451function dmmrd_add_log($message, $start = 'N/A', $end = 'N/A', $schedule_type = '', $schedule_days = []) {
    276452    $logs = get_option('dmmrd_logs', []);
    277453
    278     array_unshift($logs, [
     454    $message = sanitize_text_field((string) $message);
     455    $start   = sanitize_text_field((string) $start);
     456    $end     = sanitize_text_field((string) $end);
     457
     458    list($schedule_type, $schedule_days) = dmmrd_normalize_log_schedule_meta($schedule_type, $schedule_days);
     459
     460    $entry = [
    279461        'time'    => current_time('mysql'),
    280462        'message' => $message,
    281463        'start'   => $start,
    282         'end'     => $end
    283     ]);
    284 
    285     if ( count($logs) > 50 ) {
     464        'end'     => $end,
     465    ];
     466
     467    // Keep backward-compatibility by only storing schedule keys when we know them.
     468    if ('' !== $schedule_type) {
     469        $entry['schedule_type'] = $schedule_type;
     470        if ('custom' === $schedule_type && !empty($schedule_days)) {
     471            $entry['schedule_days'] = $schedule_days;
     472        }
     473    }
     474
     475    array_unshift($logs, $entry);
     476
     477    if (count($logs) > 50) {
    286478        $logs = array_slice($logs, 0, 50);
    287479    }
    288480
    289481    update_option('dmmrd_logs', $logs);
     482}
     483
     484
     485function dmmrd_normalize_log_schedule_meta($schedule_type, $schedule_days) {
     486    $type = strtolower(sanitize_text_field((string) $schedule_type));
     487
     488    $map = [
     489        'daily'    => 'everyday',
     490        'everyday' => 'everyday',
     491        'weekend'  => 'weekend',
     492        'custom'   => 'custom',
     493    ];
     494
     495    $type = isset($map[$type]) ? $map[$type] : '';
     496
     497    $days = [];
     498    if ('custom' === $type) {
     499        $code_to_label = [
     500            'sun' => 'Sunday',
     501            'mon' => 'Monday',
     502            'tue' => 'Tuesday',
     503            'wed' => 'Wednesday',
     504            'thu' => 'Thursday',
     505            'fri' => 'Friday',
     506            'sat' => 'Saturday',
     507        ];
     508
     509        $label_lookup = [];
     510        foreach ($code_to_label as $code => $label) {
     511            $label_lookup[strtolower($label)] = $label;
     512        }
     513
     514        foreach ((array) $schedule_days as $day) {
     515            $raw = sanitize_text_field((string) $day);
     516            if ('' === $raw) {
     517                continue;
     518            }
     519
     520            $lower = strtolower($raw);
     521            if (isset($code_to_label[$lower])) {
     522                $days[] = $code_to_label[$lower];
     523                continue;
     524            }
     525
     526            if (isset($label_lookup[$lower])) {
     527                $days[] = $label_lookup[$lower];
     528            }
     529        }
     530
     531        $days = array_values(array_unique($days));
     532    }
     533
     534    return [$type, $days];
     535}
     536
     537/**
     538 * Format a log entry schedule for the admin UI table.
     539 *
     540 * Backward compatible with older logs that don't have schedule_type/schedule_days.
     541 *
     542 * @param array $log
     543 * @return string
     544 */
     545function dmmrd_format_log_schedule_for_display($log) {
     546    $start = isset($log['start']) ? (string) $log['start'] : 'N/A';
     547    $end   = isset($log['end']) ? (string) $log['end'] : 'N/A';
     548    $range = trim($start) . ' - ' . trim($end);
     549
     550    $schedule_type = isset($log['schedule_type']) ? (string) $log['schedule_type'] : '';
     551    $schedule_days = isset($log['schedule_days']) ? (array) $log['schedule_days'] : [];
     552
     553    list($schedule_type, $schedule_days) = dmmrd_normalize_log_schedule_meta($schedule_type, $schedule_days);
     554
     555    if ('' === $schedule_type) {
     556        return $range;
     557    }
     558
     559    $label_map = [
     560        'everyday' => 'Everyday',
     561        'weekend'  => 'Weekend',
     562        'custom'   => 'Custom',
     563    ];
     564    $label = isset($label_map[$schedule_type]) ? $label_map[$schedule_type] : ucfirst($schedule_type);
     565
     566    if ('custom' === $schedule_type && !empty($schedule_days)) {
     567        $code_to_short = [
     568            'sun' => 'Sun',
     569            'mon' => 'Mon',
     570            'tue' => 'Tue',
     571            'wed' => 'Wed',
     572            'thu' => 'Thu',
     573            'fri' => 'Fri',
     574            'sat' => 'Sat',
     575        ];
     576
     577        $full_to_short = [
     578            'Sunday' => 'Sun',
     579            'Monday' => 'Mon',
     580            'Tuesday' => 'Tue',
     581            'Wednesday' => 'Wed',
     582            'Thursday' => 'Thu',
     583            'Friday' => 'Fri',
     584            'Saturday' => 'Sat',
     585        ];
     586
     587        $days_out = [];
     588        foreach ($schedule_days as $d) {
     589            $raw = sanitize_text_field((string) $d);
     590            if ('' === $raw) {
     591                continue;
     592            }
     593
     594            $lower = strtolower($raw);
     595            if (isset($code_to_short[$lower])) {
     596                $days_out[] = $code_to_short[$lower];
     597                continue;
     598            }
     599
     600            if (isset($full_to_short[ucfirst(strtolower($raw))])) {
     601                $days_out[] = $full_to_short[ucfirst(strtolower($raw))];
     602            }
     603        }
     604
     605        $days_out = array_values(array_unique($days_out));
     606        if (!empty($days_out)) {
     607            $label .= ' (' . implode(', ', $days_out) . ')';
     608        }
     609    }
     610
     611    return $label . ' (' . $range . ')';
    290612}
    291613
     
    302624});
    303625
     626function dmmrd_is_recurring_active() {
     627    $type  = get_option('dmmrd_repeat_type');
     628    $start = get_option('dmmrd_daily_start');
     629    $end   = get_option('dmmrd_daily_end');
     630
     631    if (!$type || !$start || !$end) {
     632        return false;
     633    }
     634
     635    $timezone = new DateTimeZone('Asia/Kolkata');
     636    $now_dt = new DateTime('now', $timezone);
     637    $now_minutes = ((int) $now_dt->format('H')) * 60 + (int) $now_dt->format('i');
     638
     639    $start_dt = DateTime::createFromFormat('H:i', (string) $start, $timezone);
     640    $end_dt = DateTime::createFromFormat('H:i', (string) $end, $timezone);
     641    if (!$start_dt || !$end_dt) {
     642        return false;
     643    }
     644
     645    $start_minutes = ((int) $start_dt->format('H')) * 60 + (int) $start_dt->format('i');
     646    $end_minutes   = ((int) $end_dt->format('H')) * 60 + (int) $end_dt->format('i');
     647    $crosses_midnight = ($start_minutes > $end_minutes);
     648
     649    $today = strtolower($now_dt->format('D'));
     650    $yesterday_dt = clone $now_dt;
     651    $yesterday_dt->modify('-1 day');
     652    $yesterday = strtolower($yesterday_dt->format('D'));
     653
     654    $is_allowed_day = dmmrd_is_repeat_day_allowed($type, $today);
     655    $is_allowed_yesterday = dmmrd_is_repeat_day_allowed($type, $yesterday);
     656
     657    if (!$crosses_midnight) {
     658        if (!$is_allowed_day) {
     659            return false;
     660        }
     661        return ($now_minutes >= $start_minutes && $now_minutes <= $end_minutes);
     662    }
     663
     664    $in_late_window = ($now_minutes >= $start_minutes);
     665    $in_early_window = ($now_minutes <= $end_minutes);
     666
     667    if ($in_late_window) {
     668        return $is_allowed_day;
     669    }
     670
     671    if ($in_early_window) {
     672        return $is_allowed_yesterday;
     673    }
     674
     675    return false;
     676}
     677
     678function dmmrd_is_repeat_day_allowed($type, $day) {
     679    $day = strtolower((string) $day);
     680
     681    if ($type === 'daily') {
     682        return true;
     683    }
     684
     685    if ($type === 'weekend') {
     686        return in_array($day, ['sat', 'sun'], true);
     687    }
     688
     689    if ($type === 'custom') {
     690        $saved_days = array_map('strtolower', (array) get_option('dmmrd_repeat_days', []));
     691        return in_array($day, $saved_days, true);
     692    }
     693
     694    return false;
     695}
     696
     697function dmmrd_maybe_log_recurring_state($is_active) {
     698    $state_key = 'dmmrd_recurring_last_state';
     699    $new_state = $is_active ? 'on' : 'off';
     700    $last_state = get_option($state_key, '');
     701
     702    if ($last_state === $new_state) {
     703        return;
     704    }
     705
     706    $start = get_option('dmmrd_daily_start', 'N/A');
     707    $end = get_option('dmmrd_daily_end', 'N/A');
     708
     709    $repeat_type = (string) get_option('dmmrd_repeat_type', '');
     710    $repeat_days = (array) get_option('dmmrd_repeat_days', []);
     711
     712    if ($is_active) {
     713        dmmrd_add_log(
     714            'Recurring Maintenance started',
     715            (string) $start,
     716            (string) $end,
     717            $repeat_type,
     718            $repeat_days
     719        );
     720    } else {
     721        dmmrd_add_log(
     722            'Recurring Maintenance stopped',
     723            (string) $start,
     724            (string) $end,
     725            $repeat_type,
     726            $repeat_days
     727        );
     728    }
     729
     730    update_option($state_key, $new_state);
     731}
     732
     733add_action('template_redirect', 'dmmrd_handle_maintenance_mode');
     734
     735// add_action('wp_footer', function() {
     736//     undefined_function_test();
     737// });
  • dynamic-maintenance-mode/trunk/includes/settings-page.php

    r3485289 r3491444  
    11<?php
    22/**
    3  * Dynamic Maintenance Mode Settings Page
     3 * Dynamic Maintenance Mode Settings Page (Full Optimized Code)
    44 */
    55
     
    1919});
    2020
    21 
    22 add_action('admin_enqueue_scripts', 'dmmrd_enqueue_admin_assets');
    23 
    24 function dmmrd_enqueue_admin_assets($hook) {
    25     if ($hook !== 'toplevel_page_dmmrd-settings') {
    26         return;
    27     }
    28 
    29     wp_enqueue_script(
    30         'dmmrd-admin-script',
    31         plugin_dir_url(__DIR__) . 'assets/admin.js',
    32         ['jquery'],
    33         '1.0',
    34         true
    35     );
    36 }
     21add_action('admin_enqueue_scripts', function($hook) {
     22    if ($hook !== 'toplevel_page_dmmrd-settings') return;
     23    wp_enqueue_media();
     24});
    3725
    3826
    3927add_action('admin_init', function() {
    40     register_setting('dmmrd_settings_group', 'dmmrd_enable_mode', ['sanitize_callback' => 'absint']);
    41     register_setting('dmmrd_settings_group', 'dmmrd_mode_scope', ['sanitize_callback' => 'sanitize_text_field']);
    42     register_setting('dmmrd_settings_group', 'dmmrd_custom_page_id', ['sanitize_callback' => 'absint']);
    43     register_setting('dmmrd_settings_group', 'dmmrd_maintenance_type', ['sanitize_callback' => 'sanitize_text_field']);
    44     register_setting('dmmrd_settings_group', 'dmmrd_target_type', ['sanitize_callback' => 'sanitize_text_field']);
    45     register_setting('dmmrd_settings_group', 'dmmrd_url_keyword', ['sanitize_callback' => 'sanitize_text_field']);
    46     register_setting('dmmrd_settings_group', 'dmmrd_start_time', ['sanitize_callback' => 'dmmrd_sanitize_datetime']);
    47     register_setting('dmmrd_settings_group', 'dmmrd_end_time', ['sanitize_callback' => 'dmmrd_sanitize_datetime']);
    48     register_setting('dmmrd_settings_group', 'dmmrd_advanced_mode', ['sanitize_callback' => 'absint']);
     28    $settings = [
     29        'dmmrd_enable_mode', 'dmmrd_mode_scope', 'dmmrd_custom_page_id',
     30        'dmmrd_maintenance_type', 'dmmrd_target_type', 'dmmrd_url_keyword',
     31        'dmmrd_start_time', 'dmmrd_end_time', 'dmmrd_advanced_mode', 'dmmrd_custom_message',
     32        'dmmrd_custom_image','dmmrd_repeat_type', 'dmmrd_repeat_days', 'dmmrd_schedule_enable',
     33         'dmmrd_daily_start', 'dmmrd_daily_end','dmmrd_repeat_enable','dmmrd_enable_custom_msg',
     34         'dmmrd_enable_custom_page', 'dmmrd_custom_display_page','dmmrd_auto_maintenance_on_error',
     35    ];
     36
     37    foreach ($settings as $setting) {
     38        register_setting(
     39            'dmmrd_settings_group',
     40            $setting,
     41            [
     42                'sanitize_callback' => function($value) use ($setting) {
     43                    return dmmrd_sanitize_settings($value, $setting);
     44                },
     45            ]
     46        );
     47    }
    4948});
    5049
    51 
    52 function dmmrd_sanitize_datetime($value) {
    53     return preg_match('/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/', $value) ? $value : '';
     50function dmmrd_sanitize_settings($value, $setting = '') {
     51    $checkbox_fields = [
     52        'dmmrd_enable_mode',
     53        'dmmrd_schedule_enable',
     54        'dmmrd_repeat_enable',
     55        'dmmrd_enable_custom_msg',
     56        'dmmrd_enable_custom_page',
     57        'dmmrd_advanced_mode',
     58        'dmmrd_auto_maintenance_on_error',
     59    ];
     60
     61    if (in_array($setting, $checkbox_fields, true)) {
     62        return empty($value) ? '0' : '1';
     63    }
     64
     65    if ('dmmrd_repeat_days' === $setting) {
     66        if (!is_array($value)) {
     67            return [];
     68        }
     69
     70        $allowed_days = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
     71        $clean_days = [];
     72        foreach ($value as $day) {
     73            $day = strtolower(sanitize_text_field((string) $day));
     74            if (in_array($day, $allowed_days, true)) {
     75                $clean_days[] = $day;
     76            }
     77        }
     78
     79        return array_values(array_unique($clean_days));
     80    }
     81
     82    if ('dmmrd_custom_message' === $setting) {
     83        return wp_kses_post((string) $value);
     84    }
     85
     86    if ('dmmrd_custom_image' === $setting) {
     87        return esc_url_raw((string) $value);
     88    }
     89
     90    if (is_array($value)) {
     91        return array_map('sanitize_text_field', $value);
     92    }
     93
     94    return sanitize_text_field($value);
    5495}
    5596
     
    5798function dmmrd_settings_page_html() {
    5899   
    59 $tab = filter_input(INPUT_GET, 'tab', FILTER_SANITIZE_FULL_SPECIAL_CHARS) ?: 'settings';
     100if (isset($_POST['dmmrd_clear_logs'])) {
     101
     102    $nonce = '';
     103
     104    if (isset($_POST['_wpnonce'])) {
     105        $nonce = sanitize_text_field(
     106            wp_unslash($_POST['_wpnonce'])
     107        );
     108    }
     109
     110    if (!wp_verify_nonce($nonce, 'dmmrd_clear_logs_action')) {
     111        return;
     112    }
     113
     114    update_option('dmmrd_logs', []);
     115}
     116
    60117    ?>
    61118    <style>
    62        
    63         .dmmrd-card { background: #fff; border: 1px solid #ccd0d4; padding: 20px; margin-top: 20px; box-shadow: 0 1px 1px rgba(0,0,0,.04); }
    64         .nav-tab-wrapper { margin-bottom: 20px; }
    65         .form-table th { width: 220px; }
    66         .status-badge { padding: 4px 8px; border-radius: 4px; font-size: 11px; font-weight: bold; text-transform: uppercase; }
    67         .badge-active { background: #e7f6ed; color: #207b4d; border: 1px solid #c6e1d1; }
    68         .badge-sched { background: #fcf9e8; color: #856404; border: 1px solid #ffeeba; }
    69     </style>
     119        .dmmrd-card { background: #fff; border: 1px solid #ccd0d4; padding: 20px; margin-top: 20px; box-shadow: 0 1px 1px rgba(0,0,0,.04); border-radius: 4px; }
     120        .nav-tab-wrapper { margin-bottom: 0; }
     121        .form-table th { width: 220px; font-weight: 600; }
     122        .tab-content { display: none; margin-top: 20px; }
     123        .tab-content.active { display: block; }
     124        .sub-tab-content { display: none; }
     125        .sub-tab-content.active { display: block; }
     126        #dmmrd-image-preview { max-width: 200px; height: auto; border: 1px solid #ccc; padding: 5px; margin-bottom: 10px; border-radius: 4px; }
     127   
     128   </style>
    70129
    71130    <div class="wrap">
    72         <h1 class="wp-heading-inline">Maintenance Mode</h1>
    73         <hr class="wp-header-end">
    74        
    75         <h2 class="nav-tab-wrapper">
    76             <a href="?page=dmmrd-settings&tab=settings" class="nav-tab <?php echo $tab === 'settings' ? 'nav-tab-active' : ''; ?>">Settings</a>
    77             <a href="?page=dmmrd-settings&tab=logs" class="nav-tab <?php echo $tab === 'logs' ? 'nav-tab-active' : ''; ?>">Activity Logs</a>
     131        <h1>Maintenance Mode Settings</h1>
     132
     133            <?php
     134        $settings_updated = false;
     135
     136        if (isset($_GET['settings-updated'])) {
     137            $settings_updated = sanitize_text_field(
     138                wp_unslash($_GET['settings-updated'])
     139            );
     140        }
     141
     142        if ($settings_updated):
     143        ?>
     144    <div class="notice notice-success is-dismissible">
     145        <p><strong>Settings saved successfully!</strong></p>
     146    </div>
     147<?php endif; ?>
     148
     149        <h2 class="nav-tab-wrapper main-tabs">
     150            <a href="#settings-section" class="nav-tab nav-tab-active">Configuration</a>
     151            <a href="#logs-section" class="nav-tab">Activity Logs</a>
    78152        </h2>
    79153
    80         <?php if ($tab === 'logs') : ?>
    81     <div class="dmmrd-card">
    82         <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
    83             <h2 style="margin:0;">Recent Activities</h2>
    84            
    85             <form method="post" action="" onsubmit="return confirm('Are you sure you want to delete all logs?');">
    86                 <?php wp_nonce_field('dmmrd_clear_logs_action'); ?>
    87                 <input type="submit" name="dmmrd_clear_logs" class="button button-secondary" value="Clear All Logs">
    88             </form>
     154        <div id="logs-section" class="tab-content">
     155            <div class="dmmrd-card">
     156                <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
     157                    <h2 style="margin:0;">Recent Activities</h2>
     158                    <form method="post" action="" onsubmit="return confirm('Clear all logs?');">
     159                        <?php wp_nonce_field('dmmrd_clear_logs_action'); ?>
     160                        <input type="submit" name="dmmrd_clear_logs" class="button button-secondary" value="Clear All Logs">
     161                    </form>
     162                </div>
     163                <table class="wp-list-table widefat fixed striped">
     164                    <thead>
     165                        <tr>
     166                            <th>Date & Time</th>
     167                            <th>Activity</th>
     168                            <th>Schedule</th>
     169                        </tr>
     170                    </thead>
     171                    <tbody>
     172                        <?php
     173                        $logs = get_option('dmmrd_logs', []);
     174                        if (empty($logs)) : ?>
     175                            <tr><td colspan="3" style="text-align:center;">No logs found.</td></tr>
     176                        <?php else :
     177                            foreach (array_slice(array_reverse($logs), 0, 20) as $log) : ?>
     178                            <tr>
     179                                <td><?php echo esc_html(isset($log['time']) ? $log['time'] : ''); ?></td>
     180                                <td><strong><?php echo esc_html(isset($log['message']) ? $log['message'] : ''); ?></strong></td>
     181                                <td><?php echo esc_html(dmmrd_format_log_schedule_for_display($log)); ?></td>
     182                            </tr>
     183                        <?php endforeach; endif; ?>
     184                    </tbody>
     185                </table>
     186            </div>
    89187        </div>
    90188
    91         <table class="wp-list-table widefat fixed striped table-view-list">
    92             <thead>
    93                 <tr>
    94                     <th scope="col" class="manage-column" style="width: 20%;">Date & Time</th>
    95                     <th scope="col" class="manage-column">Activity</th>
    96                     <th scope="col" class="manage-column">Schedule (Start - End)</th>
    97                 </tr>
    98             </thead>
    99             <tbody>
    100                 <?php
    101                 $logs = get_option('dmmrd_logs', []);
    102                 if (empty($logs)) : ?>
    103                     <tr><td colspan="3" style="text-align: center; padding: 20px;">No logs recorded yet.</td></tr>
    104                 <?php else :
    105                     foreach (array_reverse($logs) as $log) : ?>
    106                     <tr>
    107                         <td><span class="dashicons dashicons-clock" style="font-size:17px; color:#646970;"></span> <?php echo esc_html($log['time']); ?></td>
    108                         <td><strong><?php echo esc_html($log['message']); ?></strong></td>
    109                         <td>
    110                             <?php if(!empty($log['start'])): ?>
    111                                 <code><?php echo esc_html($log['start']); ?></code> — <code><?php echo esc_html($log['end']); ?></code>
    112                             <?php else: ?>
    113                                 <span class="description">N/A</span>
    114                             <?php endif; ?>
    115                         </td>
    116                     </tr>
    117                 <?php endforeach; endif; ?>
    118             </tbody>
    119         </table>
    120     </div>
    121 <?php else : ?>
     189        <div id="settings-section" class="tab-content active">
    122190            <form method="post" action="options.php">
    123191                <?php settings_fields('dmmrd_settings_group'); ?>
    124                
    125                 <div class="dmmrd-card">
    126                     <h2>General Configuration</h2>
    127                     <table class="form-table" role="presentation">
    128                         <tr>
    129                             <th scope="row">Status</th>
     192
     193                <h2 class="nav-tab-wrapper sub-tabs" style="border-bottom:none; margin-top:10px;">
     194                    <a href="#general-tab" class="nav-tab nav-tab-active">General</a>
     195                    <a href="#advanced-tab" class="nav-tab">Advanced & Schedule</a>
     196                </h2>
     197
     198                <div id="general-tab" class="sub-tab-content active">
     199                    <div class="dmmrd-card">
     200                        <h2>Maintenance Controls</h2>
     201                        <table class="form-table">
     202                            <tr>
     203                                <th scope="row">Master Switch</th>
     204                                <td>
     205                                    <label>
     206                                        <input type="hidden" name="dmmrd_enable_mode" value="0">
     207                                        <input type="checkbox" id="dmmrd_toggle_status" name="dmmrd_enable_mode" value="1" <?php checked(get_option('dmmrd_enable_mode'), '1'); ?>>
     208                                        <strong>Enable Maintenance Mode</strong>
     209                                    </label>
     210                                </td>
     211                            </tr>
     212                            <tbody id="dmmrd-logic-rows">
     213                                <tr>
     214                                    <th scope="row">Who sees maintenance?</th>
     215                                    <td>
     216                                        <select name="dmmrd_mode_scope" class="regular-text">
     217                                            <option value="all" <?php selected(get_option('dmmrd_mode_scope'), 'all'); ?>>Everyone</option>
     218                                            <option value="loggedin" <?php selected(get_option('dmmrd_mode_scope'), 'loggedin'); ?>>Logged-In Only</option>
     219                                            <option value="loggedout" <?php selected(get_option('dmmrd_mode_scope'), 'loggedout'); ?>>Logged-Out Only</option>
     220                                        </select>
     221                                    </td>
     222                                </tr>
     223                                <tr>
     224                                    <th scope="row">Where to apply?</th>
     225                                    <td>
     226                                        <label><input type="radio" name="dmmrd_target_type" value="site" <?php checked(get_option('dmmrd_target_type', 'site'), 'site'); ?>> Entire Website</label><br>
     227                                        <label><input type="radio" name="dmmrd_target_type" value="page" <?php checked(get_option('dmmrd_target_type'), 'page'); ?>> Specific Page</label><br>
     228                                        <label><input type="radio" name="dmmrd_target_type" value="url" <?php checked(get_option('dmmrd_target_type'), 'url'); ?>> URL Keyword</label>
     229                                    </td>
     230                                </tr>
     231                                <tr class="target-field page-field">
     232                                    <th scope="row">Select Target Page</th>
     233                                    <td>
     234                                    <?php
     235                                    wp_dropdown_pages([
     236                                        'name' => 'dmmrd_custom_page_id',
     237                                        'selected' => esc_attr(get_option('dmmrd_custom_page_id')),
     238                                        'show_option_none' => '-- Select Page --'
     239                                    ]);
     240                                    ?>
     241                                    </td>               
     242                                </tr>
     243                               <tr class="target-field url-field">
     244                                <th scope="row">URL Keyword</th>
     245                                <td>
     246                                    <input type="text" name="dmmrd_url_keyword"
     247                                    value="<?php echo esc_attr(get_option('dmmrd_url_keyword')); ?>"
     248                                    class="regular-text" placeholder="e.g. checkout">
     249
     250                                    <p class="description" style="margin-top:5px;">
     251                                        Example: <code>checkout</code> → works on <code>yourwebsite.com/checkout</code><br>
     252                                        Example: <code>cart</code> → works on <code>yourwebsite.com/cart</code>
     253                                    </p>
     254                                </td>
     255                            </tr>
     256                            </tbody>
     257                        </table>
     258                    </div>
     259
     260                    <div id="content-settings-card" class="dmmrd-card">
     261                        <table class="form-table">
     262                            <tr>
     263                            <th scope="row">Enable Custom Message</th>
    130264                            <td>
    131                                 <label class="switch">
    132                                     <input type="checkbox" name="dmmrd_enable_mode" value="1" <?php checked(get_option('dmmrd_enable_mode'), '1'); ?>>
    133                                     <strong>Enable Maintenance Mode</strong>
     265                                <label>
     266                                    <input type="hidden" name="dmmrd_enable_custom_msg" value="0">
     267                                    <input type="checkbox" id="dmmrd_enable_custom_msg" name="dmmrd_enable_custom_msg" value="1"
     268                                    <?php checked(get_option('dmmrd_enable_custom_msg'), 1); ?>>
     269                                    Enable Custom Content
    134270                                </label>
    135271                            </td>
    136272                        </tr>
    137 
    138                         <tr>
    139                             <th scope="row">Visibility (Who sees it?)</th>
     273                           <tr class="dmmrd-custom-message-row">
     274                                <th scope="row">Custom Message</th>
     275                                <td>
     276                                    <?php
     277                                    $content = wp_kses_post(get_option('dmmrd_custom_message'));
     278
     279                                    wp_editor(
     280                                        $content,
     281                                        'dmmrd_custom_message',
     282                                        array(
     283                                            'textarea_name' => 'dmmrd_custom_message',
     284                                            'media_buttons' => true,
     285                                            'textarea_rows' => 8,
     286                                            'teeny'         => false,
     287                                            'quicktags'     => true,
     288                                        )
     289                                    );
     290                                    ?>
     291                                </td>
     292                            </tr>
     293                           
     294                            <tr>
     295                            <th scope="row">Enable Custom Page</th>
    140296                            <td>
    141                                 <select name="dmmrd_mode_scope" class="regular-text">
    142                                     <option value="all" <?php selected(esc_attr(get_option('dmmrd_mode_scope')), 'all'); ?>>Everyone (All Users)</option>
    143                                     <option value="loggedin" <?php selected(esc_attr(get_option('dmmrd_mode_scope')), 'loggedin'); ?>>Only Logged-In Users</option>
    144                                     <option value="loggedout" <?php selected(esc_attr(get_option('dmmrd_mode_scope')), 'loggedout'); ?>>Only Guest/Logged-Out Users</option>
    145                                 </select>
     297                                <label>
     298                                    <input type="hidden" name="dmmrd_enable_custom_page" value="0">
     299                                    <input type="checkbox" id="dmmrd_enable_custom_page" name="dmmrd_enable_custom_page" value="1"
     300                                    <?php checked(get_option('dmmrd_enable_custom_page'), 1); ?>>
     301                                    Enable Custom Page Display
     302                                </label>
    146303                            </td>
    147304                        </tr>
    148305
    149                         <tr>
    150                             <th scope="row">Where to apply?</th>
    151                             <td>
    152                                 <fieldset>
    153                                     <label><input type="radio" name="dmmrd_target_type" value="site" <?php checked(esc_attr(get_option('dmmrd_target_type', 'site')), 'site'); ?>> <span>Entire Website</span></label><br>
    154                                     <label><input type="radio" name="dmmrd_target_type" value="page" <?php checked(esc_attr(get_option('dmmrd_target_type')), 'page'); ?>> <span>Specific Page</span></label><br>
    155                                     <label><input type="radio" name="dmmrd_target_type" value="url" <?php checked(esc_attr(get_option('dmmrd_target_type')), 'url'); ?>> <span>URL Keyword Match</span></label>
    156                                 </fieldset>
    157                             </td>
    158                         </tr>
    159 
    160                         <tr class="target-field page-field" style="display:none;">
    161                             <th scope="row">Select Target Page</th>
     306                        <tr class="dmmrd-custom-page-row">
     307                            <th scope="row">Select Page to Show</th>
    162308                            <td>
    163309                                <?php
    164310                                wp_dropdown_pages([
    165                                     'name'              => 'dmmrd_custom_page_id',
    166                                     'selected'          => absint(get_option('dmmrd_custom_page_id')),
    167                                     'show_option_none'  => '— Select a Page —'
     311                                    'name' => 'dmmrd_custom_display_page',
     312                                    'selected' => esc_attr(get_option('dmmrd_custom_display_page')),
     313                                    'show_option_none' => '-- Select Page --'
    168314                                ]);
    169315                                ?>
     316                                <p class="description">
     317                                    Maintenance mode ke time ye page frontend par show hoga.
     318                                </p>
    170319                            </td>
    171320                        </tr>
    172 
    173                         <tr class="target-field url-keyword-field" style="display:none;">
    174                             <th scope="row">Enter Keyword</th>
     321                        </table>
     322                       
     323                    </div>
     324                   
     325                </div>
     326
     327                <div id="advanced-tab" class="sub-tab-content">
     328                    <div class="dmmrd-card">
     329                        <h2>Scheduling</h2>
     330                        <table class="form-table">
     331                             
     332                            <tr>
     333                                <th scope="row">Enable Scheduling</th>
     334                                <td>
     335                                    <label>
     336                                        <input type="hidden" name="dmmrd_schedule_enable" value="0">
     337                                        <input type="checkbox" id="dmmrd_schedule_enable" name="dmmrd_schedule_enable" value="1"
     338                                        <?php checked(get_option('dmmrd_schedule_enable'), 1); ?>>
     339                                        Enable Schedule System
     340                                    </label>
     341                                </td>
     342                            </tr>
     343                            <tbody class="schedule-wrapper">
     344                            <tr>
     345                                <th scope="row">Activation Type</th>
     346                                <td>
     347                                    <label><input type="radio" name="dmmrd_maintenance_type" value="alltime" <?php checked(get_option('dmmrd_maintenance_type', 'alltime'), 'alltime'); ?>> Always ON</label> &nbsp;
     348                                    <label><input type="radio" name="dmmrd_maintenance_type" value="schedule" <?php checked(get_option('dmmrd_maintenance_type'), 'schedule'); ?>> Timed Schedule</label>
     349                                </td>
     350                            </tr>
     351                            <tr class="schedule-fields">
     352                                <th scope="row">Start Date/Time</th>
     353                                <td><input type="datetime-local" name="dmmrd_start_time" value="<?php echo esc_attr(get_option('dmmrd_start_time')); ?>" class="regular-text"></td>
     354                            </tr>
     355                            <tr class="schedule-fields">
     356                                <th scope="row">End Date/Time</th>
     357                                <td><input type="datetime-local" name="dmmrd_end_time" value="<?php echo esc_attr(get_option('dmmrd_end_time')); ?>" class="regular-text"></td>
     358                            </tr>
     359                               
     360                          </tbody>
     361                              <tr>
     362                                <th scope="row">Enable Repeat Mode</th>
     363                                <td>
     364                                    <label>
     365                                        <input type="hidden" name="dmmrd_repeat_enable" value="0">
     366                                        <input type="checkbox" id="dmmrd_repeat_enable" name="dmmrd_repeat_enable" value="1"
     367                                        <?php checked(get_option('dmmrd_repeat_enable'), 1); ?>>
     368                                        Enable Recurring Schedule
     369                                    </label>
     370                                </td>
     371                            </tr>
     372                            <tr>
     373                                <th scope="row">Repeat Mode</th>
     374                                <td>
     375                                    <select name="dmmrd_repeat_type" id="dmmrd_repeat_type">
     376                                        <option value="">None</option>
     377                                        <option value="daily" <?php selected(get_option('dmmrd_repeat_type'),'daily'); ?>>Everyday</option>
     378                                        <option value="weekend" <?php selected(get_option('dmmrd_repeat_type'),'weekend'); ?>>Weekend</option>
     379                                        <option value="custom" <?php selected(get_option('dmmrd_repeat_type'),'custom'); ?>>Custom Days</option>
     380                                    </select>
     381                                </td>
     382                            </tr>
     383
     384                        <tr class="repeat-days" style="display:none;">
     385                            <th>Select Days</th>
    175386                            <td>
    176                                 <input type="text" name="dmmrd_url_keyword" value="<?php echo esc_attr(get_option('dmmrd_url_keyword')); ?>" class="regular-text" placeholder="e.g. checkout">
    177                                 <p class="description">If the URL contains this word, maintenance will trigger.</p>
     387                                <?php
     388                                $days = ['sun','mon','tue','wed','thu','fri','sat'];
     389                                $saved = (array)get_option('dmmrd_repeat_days');
     390                                foreach($days as $day){ ?>
     391                                    <label style="margin-right:10px;">
     392                                        <input type="checkbox" name="dmmrd_repeat_days[]" value="<?php echo esc_attr($day); ?>"
     393                                        <?php checked(in_array($day,$saved)); ?>>
     394                                        <?php echo esc_html(ucfirst($day)); ?>
     395                                    </label>
     396                                <?php } ?>
    178397                            </td>
    179398                        </tr>
    180                     </table>
    181                 </div>
    182 
    183                 <div class="dmmrd-card">
    184                     <h2>Time & Schedule</h2>
    185                     <table class="form-table">
    186                         <tr>
    187                             <th scope="row">Activation Type</th>
     399
     400                        <tr class="repeat-time" style="display:none;">
     401                            <th>Daily Time</th>
    188402                            <td>
    189                                 <label><input type="radio" name="dmmrd_maintenance_type" value="alltime" <?php checked(esc_attr(get_option('dmmrd_maintenance_type', 'alltime')), 'alltime'); ?>> <strong>Always ON</strong></label> &nbsp;&nbsp;
    190                                 <label><input type="radio" name="dmmrd_maintenance_type" value="schedule" <?php checked(esc_attr(get_option('dmmrd_maintenance_type')), 'schedule'); ?>> <strong>Timed Schedule</strong></label>
     403                                <input type="time" name="dmmrd_daily_start"  value="<?php echo esc_attr(get_option('dmmrd_daily_start')); ?>">
     404
     405                                to
     406
     407                                <input type="time" name="dmmrd_daily_end"  value="<?php echo esc_attr(get_option('dmmrd_daily_end')); ?>">
    191408                            </td>
    192409                        </tr>
    193 
    194                         <tr class="schedule-fields" style="display:none;">
    195                             <th scope="row">Start Date/Time</th>
    196                             <td><input type="datetime-local" name="dmmrd_start_time" value="<?php echo esc_attr(get_option('dmmrd_start_time')); ?>" class="regular-text"></td>
    197                         </tr>
    198 
    199                         <tr class="schedule-fields" style="display:none;">
    200                             <th scope="row">End Date/Time</th>
    201                             <td><input type="datetime-local" name="dmmrd_end_time" value="<?php echo esc_attr(get_option('dmmrd_end_time')); ?>" class="regular-text"></td>
    202                         </tr>
    203                     </table>
    204                 </div>
    205 
     410                       
     411                        </table>
     412                    </div>
    206413                <div class="dmmrd-card">
    207414                    <h2>Advanced Settings</h2>
     
    211418                            <td>
    212419                                <label>
    213                                     <input type="checkbox" name="dmmrd_advanced_mode" value="1" <?php checked((int)get_option('dmmrd_advanced_mode'), 1); ?>>
     420                                    <input type="hidden" name="dmmrd_advanced_mode" value="0">
     421                                    <input type="checkbox" name="dmmrd_advanced_mode" value="1" <?php checked(get_option('dmmrd_advanced_mode', 1), 1); ?>>
    214422                                    <strong>Enable Error Logging</strong>
    215423                                </label>
     
    217425                            </td>
    218426                        </tr>
     427
     428                        <tr>
     429                <th scope="row">Auto Maintenance on Error</th>
     430                <td>
     431                    <label>
     432                        <input type="hidden" name="dmmrd_auto_maintenance_on_error" value="0">
     433                        <input type="checkbox" name="dmmrd_auto_maintenance_on_error" value="1"
     434                        <?php checked(get_option('dmmrd_auto_maintenance_on_error'), 1); ?>>
     435                        <strong>Enable Auto Maintenance on Critical Error</strong>
     436                    </label>
     437                    <p class="description">
     438                        Agar site me fatal error aaye to automatically maintenance mode ON ho jayega.
     439                    </p>
     440                </td>
     441            </tr>
    219442                    </table>
    220443                </div>
    221 
    222                 <?php submit_button('Save Maintenance Settings', 'primary large'); ?>
     444            </div>
     445                <div style="margin-top:20px;">
     446                    <?php submit_button('Save All Settings', 'primary large'); ?>
     447                </div>
    223448            </form>
    224 
    225             <script>
    226             jQuery(document).ready(function($) {
    227                 function toggleFields() {
    228                    
    229                     var target = $('input[name="dmmrd_target_type"]:checked').val();
    230                     $('.target-field').hide();
    231                     if(target === 'page') $('.page-field').show();
    232                     if(target === 'url') $('.url-keyword-field').show();
    233 
    234                  
    235                     var type = $('input[name="dmmrd_maintenance_type"]:checked').val();
    236                     if(type === 'schedule') $('.schedule-fields').show();
    237                     else $('.schedule-fields').hide();
    238                 }
    239 
    240                 $('input').on('change', toggleFields);
    241                 toggleFields();
    242             });
    243             </script>
    244         <?php endif; ?>
     449        </div>
    245450    </div>
     451
     452  <script type="text/javascript">
     453jQuery(document).ready(function($) {
     454
     455    $('.nav-tab-wrapper a').on('click', function(e) {
     456        e.preventDefault();
     457        var target = $(this).attr('href');
     458        $(this).addClass('nav-tab-active').siblings().removeClass('nav-tab-active');
     459       
     460        if($(this).parent().hasClass('main-tabs')) {
     461            $('.tab-content').removeClass('active').hide();
     462            $(target).addClass('active').fadeIn();
     463        } else {
     464            $('.sub-tab-content').removeClass('active').hide();
     465            $(target).addClass('active').fadeIn();
     466        }
     467    });
     468
     469    function refreshUI() {
     470
     471        var isEnabled = $('#dmmrd_toggle_status').is(':checked');
     472        $('#dmmrd-logic-rows, #content-settings-card').toggle(isEnabled);
     473
     474       
     475        var target = $('input[name="dmmrd_target_type"]:checked').val();
     476        $('.target-field').hide();
     477        if(target === 'page') $('.page-field').show();
     478        if(target === 'url') $('.url-field').show();
     479
     480        var customMsgEnabled = $('#dmmrd_enable_custom_msg').is(':checked');
     481        $('.dmmrd-custom-message-row').toggle(customMsgEnabled);
     482
     483        var mType = $('input[name="dmmrd_maintenance_type"]:checked').val();
     484        $('.schedule-fields').toggle(mType === 'schedule');
     485            var scheduleEnabled = $('#dmmrd_schedule_enable').is(':checked');
     486
     487            $('.schedule-wrapper').toggle(scheduleEnabled);
     488       
     489       var repeatEnabled = $('#dmmrd_repeat_enable').is(':checked');
     490        var repeatType = $('#dmmrd_repeat_type').val();
     491
     492        $('#dmmrd_repeat_type').closest('tr').toggle(repeatEnabled);
     493
     494        $('#dmmrd_repeat_type').prop('disabled', !repeatEnabled);
     495
     496        var customPageEnabled = $('#dmmrd_enable_custom_page').is(':checked');
     497        $('.dmmrd-custom-page-row').toggle(customPageEnabled);
     498       
     499        $('.repeat-days').hide();
     500        $('.repeat-time').hide();
     501       
     502        if (repeatEnabled) {
     503
     504            if (repeatType === 'daily' || repeatType === 'weekend') {
     505                $('.repeat-time').fadeIn(150);
     506            }
     507
     508            if (repeatType === 'custom') {
     509                $('.repeat-days').fadeIn(150);
     510                $('.repeat-time').fadeIn(150);
     511            }
     512        }
     513    }
     514
     515    $('#dmmrd_toggle_status').on('change', refreshUI);
     516    $('input[name="dmmrd_target_type"]').on('change', refreshUI);
     517    $('input[name="dmmrd_maintenance_type"]').on('change', refreshUI);
     518    $('#dmmrd_repeat_type').on('change', refreshUI);
     519    $('#dmmrd_repeat_enable').on('change', refreshUI);
     520    $('#dmmrd_schedule_enable').on('change', refreshUI);
     521    $('#dmmrd_enable_custom_msg').on('change', refreshUI);
     522    $('#dmmrd_enable_custom_page').on('change', refreshUI);
     523    refreshUI();
     524
     525    var frame;
     526    $('#upload_img_btn').on('click', function(e) {
     527        e.preventDefault();
     528        if (frame) { frame.open(); return; }
     529
     530        frame = wp.media({
     531            title: 'Select Image',
     532            multiple: false
     533        });
     534
     535        frame.on('select', function() {
     536            var attachment = frame.state().get('selection').first().toJSON();
     537            $('#dmmrd_custom_image_url').val(attachment.url);
     538            $('#dmmrd-image-preview').attr('src', attachment.url).show();
     539        });
     540
     541        frame.open();
     542    });
     543
     544    $('#remove_img_btn').on('click', function() {
     545        $('#dmmrd_custom_image_url').val('');
     546        $('#dmmrd-image-preview').hide();
     547    });
     548
     549});
     550
     551</script>
    246552    <?php
    247553}
  • dynamic-maintenance-mode/trunk/readme.txt

    r3485381 r3491444  
    11=== Dynamic Maintenance Mode ===
    22Contributors: robustdecoders, pradeepshekhawat
    3 Tags: maintenance mode, coming soon, site offline, maintenance plugin, wordpress maintenance
     3Tags: maintenance mode, coming soon, site offline, robust decoders
    44Requires at least: 5.0
    55Tested up to: 6.9
    66Requires PHP: 7.0
    7 Stable tag: 1.1.1
     7Stable tag: 2.0.0
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    1010
    11 A powerful and flexible maintenance mode plugin with scheduling, logging, and advanced control options.
     11Enable a flexible maintenance mode with scheduling, custom page redirection, and user scope options. 
    1212
    13 == Description ==
     13== Description == 
     14Dynamic Maintenance Mode allows administrators to activate maintenance mode for all users or only non-logged-in visitors. You can also set a custom redirect page and schedule automatic start/end times. 
    1415
    15 Dynamic Maintenance Mode is a powerful WordPress plugin that gives you full control over your website maintenance.
     16**Key Features:** 
     17- Enable maintenance mode for all visitors or just guests 
     18- Set a custom page to display during maintenance 
     19- Schedule start and end time for automatic mode activation 
     20- Easy-to-use settings panel under the WordPress admin 
    1621
    17 You can enable maintenance mode for the entire site, specific pages, or based on URL keywords. It also supports scheduling and detailed activity logging.
    18 
    19 ✨ **Key Features:**
    20 
    21 - Enable maintenance mode for entire site, specific page, or URL keyword 
    22 - Show maintenance for all users, only logged-in users, or only visitors 
    23 - Schedule maintenance with start and end time 
    24 - Activity logs with timestamps 
    25 - Advanced error logging system (optional) 
    26 - Auto log cleanup option 
    27 - WooCommerce shop page compatibility 
    28 - Clean and user-friendly admin interface 
    29 
    30 Perfect for developers, agencies, and website owners.
    31 
    32 == Installation ==
    33 
     22== Installation == 
    34231. Upload the plugin ZIP via Plugins > Add New > Upload Plugin 
    35242. Activate the plugin through the 'Plugins' menu 
    36 3. Navigate to **Maintenance Mode** in the admin panel 
    37 4. Configure settings as per your requirement 
     253. Navigate to **Settings > Dynamic Maintenance Mode** to configure options 
    3826
    39 == Frequently Asked Questions ==
     27== Frequently Asked Questions == 
    4028
    4129= Can I show a custom page during maintenance? = 
    42 Yes, you can select any page as your maintenance page.
     30Yes, you can choose any published page to display as your maintenance page. 
    4331
    44 = Will admins be able to access the site? = 
    45 Yes, depending on your selected visibility settings.
     32= Will administrators be able to access the site during maintenance? = 
     33Yes, if you select the "Guests only" option. 
    4634
    47 = Does it support scheduling? = 
    48 Yes, you can set start and end time for automatic activation.
     35= How does the scheduling work? = 
     36The plugin checks your set start and end time and enables/disables maintenance mode automatically. 
    4937
    50 = Does it log activities? = 
    51 Yes, it maintains logs for maintenance events and errors (if enabled).
     38== Screenshots == 
     391. Settings panel in admin 
     402. Maintenance mode page preview 
     413. Scheduling options interface 
    5242
    53 == Screenshots ==
     43== Changelog == 
    5444
    55 1. Settings panel with full configuration options 
    56 2. Activity logs with maintenance tracking 
    57 3. Frontend maintenance mode display
    58 == Changelog ==
     45= 2.0.0 = 
     46* Initial release 
     47* Maintenance mode toggle 
     48* Custom redirect page 
     49* Schedule start and end time 
     50* Role-based access control 
    5951
    60 = 1.1.1 =
    61 * Added advanced error logging system 
    62 * Added auto log cleanup feature 
    63 * Improved maintenance activity logs (with schedule tracking) 
    64 * UI improvements in admin panel 
    65 * Bug fixes and performance improvements 
    66 
    67 == Upgrade Notice ==
    68 
    69 = 1.1.1 =
    70 Recommended update for improved logging system and stability.
     52== Upgrade Notice == 
     53= 2.0.0 = 
     54Initial stable release with all main features.
Note: See TracChangeset for help on using the changeset viewer.