settings = mmbd_get_settings(); add_action( 'init', array( $this, 'check_secret_phrase' ), 1 ); add_action( 'template_redirect', array( $this, 'maybe_display_maintenance' ), 1 ); add_action( 'mmbd_maintenance_head', array( $this, 'print_module_styles' ), 1 ); add_action( 'mmbd_maintenance_head', array( $this, 'output_analytics' ) ); add_action( 'mmbd_maintenance_footer', array( $this, 'output_social_links' ) ); add_action( 'mmbd_maintenance_footer', array( $this, 'print_module_scripts' ), 99 ); } public function check_secret_phrase() { $secret_phrase = trim( $this->settings['secret_phrase'] ); if ( empty( $secret_phrase ) ) { return; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public bypass URL, no state change without valid phrase if ( isset( $_GET['mmbd_bypass'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $provided = sanitize_text_field( wp_unslash( $_GET['mmbd_bypass'] ) ); if ( hash_equals( $secret_phrase, $provided ) ) { $this->set_bypass_cookie(); wp_safe_redirect( remove_query_arg( 'mmbd_bypass' ) ); exit; } } } private function set_bypass_cookie() { $duration = absint( $this->settings['cookie_duration'] ); $expiry = time() + ( $duration * DAY_IN_SECONDS ); $cookie_value = $this->generate_cookie_value( $expiry ); setcookie( 'mmbd_bypass', $cookie_value, array( 'expires' => $expiry, 'path' => COOKIEPATH, 'domain' => COOKIE_DOMAIN, 'secure' => is_ssl(), 'httponly' => true, 'samesite' => 'Lax', ) ); $_COOKIE['mmbd_bypass'] = $cookie_value; } private function generate_cookie_value( $expiry ) { $data = $expiry . '|' . get_current_blog_id(); $hash = hash_hmac( 'sha256', $data, wp_salt( 'auth' ) ); return $data . '|' . $hash; } private function verify_bypass_cookie() { if ( ! isset( $_COOKIE['mmbd_bypass'] ) ) { return false; } $cookie = sanitize_text_field( wp_unslash( $_COOKIE['mmbd_bypass'] ) ); $parts = explode( '|', $cookie ); if ( count( $parts ) !== 3 ) { return false; } list( $expiry, $blog_id, $hash ) = $parts; if ( (int) $expiry < time() ) { return false; } if ( (int) $blog_id !== get_current_blog_id() ) { return false; } $expected = hash_hmac( 'sha256', $expiry . '|' . $blog_id, wp_salt( 'auth' ) ); return hash_equals( $expected, $hash ); } public function maybe_display_maintenance() { if ( $this->is_preview_mode() ) { $this->display_maintenance_page(); return; } if ( empty( $this->settings['enabled'] ) ) { return; } if ( $this->can_bypass() ) { return; } $this->display_maintenance_page(); } private function is_preview_mode() { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only preview check if ( ! isset( $_GET['mmbd_preview'] ) || sanitize_text_field( wp_unslash( $_GET['mmbd_preview'] ) ) !== '1' ) { return false; } return is_user_logged_in() && current_user_can( 'manage_options' ); } public function can_bypass() { if ( $this->is_login_page() ) { return true; } if ( wp_doing_ajax() ) { return true; } if ( $this->is_rest_request() && is_user_logged_in() ) { return true; } if ( wp_doing_cron() ) { return true; } if ( $this->can_bypass_by_role() ) { return true; } if ( $this->can_bypass_by_ip() ) { return true; } if ( $this->verify_bypass_cookie() ) { return true; } return apply_filters( 'mmbd_can_bypass', false, $this->settings ); } private function is_login_page() { $pagenow = isset( $GLOBALS['pagenow'] ) ? $GLOBALS['pagenow'] : ''; return in_array( $pagenow, array( 'wp-login.php', 'wp-register.php' ), true ); } private function is_rest_request() { if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) { return true; } $prefix = rest_get_url_prefix(); $uri = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : ''; return strpos( $uri, '/' . $prefix . '/' ) !== false; } private function can_bypass_by_role() { if ( ! is_user_logged_in() ) { return false; } $roles = $this->settings['bypass_roles']; if ( empty( $roles ) || ! is_array( $roles ) ) { return false; } $user = wp_get_current_user(); foreach ( $roles as $role ) { if ( in_array( $role, (array) $user->roles, true ) ) { return true; } } return false; } private function can_bypass_by_ip() { $whitelist = trim( $this->settings['ip_whitelist'] ); if ( empty( $whitelist ) ) { return false; } $visitor_ip = $this->get_visitor_ip(); $ips = array_filter( array_map( 'trim', explode( "\n", $whitelist ) ) ); foreach ( $ips as $ip ) { if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) { continue; } if ( $visitor_ip === $ip ) { return true; } } return false; } private function get_visitor_ip() { $headers = array( 'HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'REMOTE_ADDR' ); foreach ( $headers as $header ) { if ( ! empty( $_SERVER[ $header ] ) ) { $ip = sanitize_text_field( wp_unslash( $_SERVER[ $header ] ) ); if ( strpos( $ip, ',' ) !== false ) { $ip = trim( explode( ',', $ip )[0] ); } if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) { return $ip; } } } return ''; } private function enqueue_template_assets( $template_id ) { $css_file = MMBD_PLUGIN_DIR . 'assets/css/templates/' . $template_id . '.css'; $css_url = MMBD_PLUGIN_URL . 'assets/css/templates/' . $template_id . '.css'; if ( file_exists( $css_file ) ) { wp_register_style( 'mmbd-template-' . $template_id, $css_url, array(), MMBD_VERSION ); wp_enqueue_style( 'mmbd-template-' . $template_id ); } if ( 'countdown' === $template_id ) { $js_file = MMBD_PLUGIN_DIR . 'assets/js/countdown.js'; $js_url = MMBD_PLUGIN_URL . 'assets/js/countdown.js'; if ( file_exists( $js_file ) ) { wp_register_script( 'mmbd-countdown', $js_url, array(), MMBD_VERSION, true ); $countdown_date = ! empty( $this->settings['countdown_date'] ) ? $this->settings['countdown_date'] : ''; wp_add_inline_script( 'mmbd-countdown', 'var mmbdCountdown = ' . wp_json_encode( array( 'targetDate' => $countdown_date ) ) . ';', 'before' ); wp_enqueue_script( 'mmbd-countdown' ); } } } public function print_module_styles() { wp_print_styles( 'mmbd-modules' ); wp_print_styles( 'mmbd-gtag' ); } public function print_module_scripts() { wp_print_scripts( 'mmbd-gtag' ); } private function enqueue_module_assets() { wp_register_style( 'mmbd-modules', MMBD_PLUGIN_URL . 'assets/css/modules.css', array(), MMBD_VERSION ); wp_enqueue_style( 'mmbd-modules' ); } public function output_analytics() { $analytics_id = isset( $this->settings['analytics_id'] ) ? trim( $this->settings['analytics_id'] ) : ''; if ( empty( $analytics_id ) ) { return; } if ( ! preg_match( '/^G-[A-Z0-9]+$/i', $analytics_id ) ) { return; } $escaped_id = esc_attr( $analytics_id ); wp_register_script( 'mmbd-gtag', 'https://www.googletagmanager.com/gtag/js?id=' . $escaped_id, array(), null, false ); wp_enqueue_script( 'mmbd-gtag' ); wp_add_inline_script( 'mmbd-gtag', "window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag('js',new Date());gtag('config','" . esc_js( $analytics_id ) . "');" ); } public function output_social_links() { $platforms = array( 'facebook' => array( 'url' => isset( $this->settings['social_facebook'] ) ? $this->settings['social_facebook'] : '', 'label' => 'Facebook', 'icon' => '', ), 'twitter' => array( 'url' => isset( $this->settings['social_twitter'] ) ? $this->settings['social_twitter'] : '', 'label' => 'Twitter / X', 'icon' => '', ), 'instagram' => array( 'url' => isset( $this->settings['social_instagram'] ) ? $this->settings['social_instagram'] : '', 'label' => 'Instagram', 'icon' => '', ), 'linkedin' => array( 'url' => isset( $this->settings['social_linkedin'] ) ? $this->settings['social_linkedin'] : '', 'label' => 'LinkedIn', 'icon' => '', ), ); $has_links = false; foreach ( $platforms as $platform ) { if ( ! empty( $platform['url'] ) ) { $has_links = true; break; } } if ( ! $has_links ) { return; } echo ''; } public function display_maintenance_page() { status_header( 503 ); header( 'Retry-After: 3600' ); header( 'Content-Type: text/html; charset=utf-8' ); nocache_headers(); $message = wp_kses_post( $this->settings['message'] ); $message = apply_filters( 'mmbd_maintenance_message', $message ); // Get template ID and enqueue assets $template_id = isset( $this->settings['template'] ) ? $this->settings['template'] : 'classic'; $this->enqueue_template_assets( $template_id ); $this->enqueue_module_assets(); $template = $this->locate_template(); if ( $template ) { include $template; } else { wp_die( wp_kses_post( $message ), esc_html__( 'Maintenance Mode', 'devlab-maintenance-mode' ), array( 'response' => 503, 'back_link' => false ) ); } exit; } private function locate_template() { $id = isset( $this->settings['template'] ) ? $this->settings['template'] : 'classic'; return MMBD_Templates::get_template_path( $id ); } } new MMBD_Maintenance();