Changeset 3491444
- Timestamp:
- 03/26/2026 05:31:53 AM (2 days ago)
- Location:
- dynamic-maintenance-mode/trunk
- Files:
-
- 4 edited
-
dynamic-maintenance-mode.php (modified) (1 diff)
-
includes/functions.php (modified) (5 diffs)
-
includes/settings-page.php (modified) (5 diffs)
-
readme.txt (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
dynamic-maintenance-mode/trunk/dynamic-maintenance-mode.php
r3485289 r3491444 3 3 * Plugin Name: Dynamic Maintenance Mode 4 4 * Description: Enable maintenance mode with custom page, user scope and scheduling. 5 * Version: 1.1.15 * Version: 2.0.0 6 6 * License: GPLv2 or later 7 7 * Author: robustdecoders -
dynamic-maintenance-mode/trunk/includes/functions.php
r3485289 r3491444 1 1 <?php 2 2 defined('ABSPATH') || exit; 3 3 ob_start(); 4 5 function 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 29 function dmmrd_clear_all_output_buffers() { 30 while (ob_get_level() > 0) { 31 @ob_end_clean(); 32 } 33 } 34 35 function 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 62 function 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;">🛠️</div>'; 79 } 80 81 echo '<div class="dmmrd-content">' . wp_kses_post(wpautop($message)) . '</div>'; 82 echo '</div></body></html>'; 83 } 84 85 function 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 } 4 120 function dmmrd_handle_maintenance_mode() 5 121 { 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 } 7 138 8 139 $scope = get_option('dmmrd_mode_scope', 'all'); … … 44 175 $now_ts = (new DateTime('now', new DateTimeZone('Asia/Kolkata')))->getTimestamp(); 45 176 46 if ($type === 'alltime') { 177 if ($type === 'alltime') { 178 if ($repeat_enabled && !$repeat_active) { 179 return; 180 } 181 182 if (!$repeat_enabled) { 47 183 dmmrd_add_log( 48 184 '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 197 if ($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 51 216 ); 52 217 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 } 71 219 } 72 220 } … … 86 234 function dmmrd_show_maintenance_notice() { 87 235 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 276 function 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">🛠️</span>'; 285 } 286 287 echo '<div class="dmmrd-content">' . wp_kses_post((string) $content_html) . '</div>'; 288 echo '</div></body></html>'; 289 } 140 290 add_action('wp', 'dmmrd_show_shop_page_notice'); 141 291 function dmmrd_show_shop_page_notice() … … 200 350 201 351 function 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) { 218 367 return false; 219 368 } 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 246 439 ); 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 451 function dmmrd_add_log($message, $start = 'N/A', $end = 'N/A', $schedule_type = '', $schedule_days = []) { 276 452 $logs = get_option('dmmrd_logs', []); 277 453 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 = [ 279 461 'time' => current_time('mysql'), 280 462 'message' => $message, 281 463 '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) { 286 478 $logs = array_slice($logs, 0, 50); 287 479 } 288 480 289 481 update_option('dmmrd_logs', $logs); 482 } 483 484 485 function 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 */ 545 function 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 . ')'; 290 612 } 291 613 … … 302 624 }); 303 625 626 function 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 678 function 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 697 function 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 733 add_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 1 1 <?php 2 2 /** 3 * Dynamic Maintenance Mode Settings Page 3 * Dynamic Maintenance Mode Settings Page (Full Optimized Code) 4 4 */ 5 5 … … 19 19 }); 20 20 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 } 21 add_action('admin_enqueue_scripts', function($hook) { 22 if ($hook !== 'toplevel_page_dmmrd-settings') return; 23 wp_enqueue_media(); 24 }); 37 25 38 26 39 27 add_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 } 49 48 }); 50 49 51 52 function dmmrd_sanitize_datetime($value) { 53 return preg_match('/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/', $value) ? $value : ''; 50 function 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); 54 95 } 55 96 … … 57 98 function dmmrd_settings_page_html() { 58 99 59 $tab = filter_input(INPUT_GET, 'tab', FILTER_SANITIZE_FULL_SPECIAL_CHARS) ?: 'settings'; 100 if (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 60 117 ?> 61 118 <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> 70 129 71 130 <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> 78 152 </h2> 79 153 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> 89 187 </div> 90 188 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"> 122 190 <form method="post" action="options.php"> 123 191 <?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> 130 264 <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 134 270 </label> 135 271 </td> 136 272 </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> 140 296 <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> 146 303 </td> 147 304 </tr> 148 305 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> 162 308 <td> 163 309 <?php 164 310 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 --' 168 314 ]); 169 315 ?> 316 <p class="description"> 317 Maintenance mode ke time ye page frontend par show hoga. 318 </p> 170 319 </td> 171 320 </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> 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> 175 386 <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 } ?> 178 397 </td> 179 398 </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> 188 402 <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> 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')); ?>"> 191 408 </td> 192 409 </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> 206 413 <div class="dmmrd-card"> 207 414 <h2>Advanced Settings</h2> … … 211 418 <td> 212 419 <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); ?>> 214 422 <strong>Enable Error Logging</strong> 215 423 </label> … … 217 425 </td> 218 426 </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> 219 442 </table> 220 443 </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> 223 448 </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> 245 450 </div> 451 452 <script type="text/javascript"> 453 jQuery(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> 246 552 <?php 247 553 } -
dynamic-maintenance-mode/trunk/readme.txt
r3485381 r3491444 1 1 === Dynamic Maintenance Mode === 2 2 Contributors: robustdecoders, pradeepshekhawat 3 Tags: maintenance mode, coming soon, site offline, maintenance plugin, wordpress maintenance3 Tags: maintenance mode, coming soon, site offline, robust decoders 4 4 Requires at least: 5.0 5 5 Tested up to: 6.9 6 6 Requires PHP: 7.0 7 Stable tag: 1.1.17 Stable tag: 2.0.0 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html 10 10 11 A powerful and flexible maintenance mode plugin with scheduling, logging, and advanced control options. 11 Enable a flexible maintenance mode with scheduling, custom page redirection, and user scope options. 12 12 13 == Description == 13 == Description == 14 Dynamic 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. 14 15 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 16 21 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 == 34 23 1. Upload the plugin ZIP via Plugins > Add New > Upload Plugin 35 24 2. 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 25 3. Navigate to **Settings > Dynamic Maintenance Mode** to configure options 38 26 39 == Frequently Asked Questions == 27 == Frequently Asked Questions == 40 28 41 29 = Can I show a custom page during maintenance? = 42 Yes, you can select any page as your maintenance page.30 Yes, you can choose any published page to display as your maintenance page. 43 31 44 = Will admin s 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? = 33 Yes, if you select the "Guests only" option. 46 34 47 = Does it support scheduling? =48 Yes, you can set start and end time for automatic activation. 35 = How does the scheduling work? = 36 The plugin checks your set start and end time and enables/disables maintenance mode automatically. 49 37 50 = Does it log activities? = 51 Yes, it maintains logs for maintenance events and errors (if enabled). 38 == Screenshots == 39 1. Settings panel in admin 40 2. Maintenance mode page preview 41 3. Scheduling options interface 52 42 53 == Screenshots ==43 == Changelog == 54 44 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 59 51 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 = 54 Initial stable release with all main features.
Note: See TracChangeset
for help on using the changeset viewer.