'no', 'mode' => 'soon', // soon | maintenance 'headline' => '', 'message' => '', 'logo' => '', 'bg' => '#f6f5f2', 'bg_image' => '', 'text' => '#1d1d1f', 'accent' => '#111111', 'end' => '', // Site-local Y-m-d\TH:i. Turns itself off after this. 'countdown' => 'yes', 'contact' => '', // Email shown on the page. 'staff_link' => 'yes', // Small "Staff login" link. 'noindex' => 'yes', // Coming soon: ask search engines not to index the page. 'roles' => array( 'administrator', 'shop_manager', 'editor' ), 'ips' => '', 'paths' => '', 'token' => '', ); } public function settings() { if ( null === $this->settings ) { $saved = get_option( self::OPTION, array() ); $this->settings = wp_parse_args( is_array( $saved ) ? $saved : array(), self::defaults() ); } return $this->settings; } public function init() { add_filter( 'bylt_settings_tabs', array( $this, 'settings_tab' ) ); add_action( 'bylt_settings_tab_maintenance', array( $this, 'render_settings' ) ); add_action( 'admin_post_bylt_maintenance_save', array( $this, 'save_settings' ) ); add_action( 'template_redirect', array( $this, 'gate' ), 0 ); add_action( 'admin_bar_menu', array( $this, 'admin_bar' ), 99 ); add_action( 'wp_enqueue_scripts', array( $this, 'admin_bar_css' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'admin_bar_css' ) ); } /* --------------------------------------------------------------------- * State * ------------------------------------------------------------------- */ private function end_time() { $end = $this->settings()['end']; if ( ! $end ) { return 0; } try { $d = new DateTime( $end, wp_timezone() ); return $d->getTimestamp(); } catch ( Exception $e ) { return 0; } } /** On, and not past its end time. */ public function is_on() { if ( 'yes' !== $this->settings()['enabled'] ) { return false; } $end = $this->end_time(); return ! $end || time() < $end; } private function token() { return (string) $this->settings()['token']; } public function preview_url() { return $this->token() ? add_query_arg( 'bylt_preview', $this->token(), home_url( '/' ) ) : ''; } private function cookie_value() { return wp_hash( 'bylt_mm|' . $this->token() ); } /** Who sees the real site. */ public function can_bypass() { if ( is_user_logged_in() ) { $user = wp_get_current_user(); if ( array_intersect( (array) $user->roles, (array) $this->settings()['roles'] ) || is_super_admin() ) { return true; } } if ( Bylt_Ip::in_list( Bylt_Ip::client(), Bylt_Ip::parse_list( $this->settings()['ips'] ) ) ) { return true; } return $this->token() && isset( $_COOKIE[ self::COOKIE ] ) && hash_equals( $this->cookie_value(), sanitize_text_field( wp_unslash( $_COOKIE[ self::COOKIE ] ) ) ); } private static function path() { $uri = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '/'; $path = (string) wp_parse_url( $uri, PHP_URL_PATH ); $home = (string) wp_parse_url( home_url( '/' ), PHP_URL_PATH ); return '/' . ltrim( substr( $path, strlen( rtrim( $home, '/' ) ) ), '/' ); } private function always_open() { if ( is_admin() || wp_doing_ajax() || wp_doing_cron() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) ) { return true; } // phpcs:ignore WordPress.Security.NonceVerification -- routing only. if ( isset( $_GET['wc-api'] ) || isset( $_GET['rest_route'] ) || is_robots() ) { return true; } $path = self::path(); if ( 0 === strpos( $path, '/wc-api/' ) || 0 === strpos( $path, '/' . rest_get_url_prefix() . '/' ) ) { return true; } foreach ( preg_split( '/\r\n|\r|\n/', (string) $this->settings()['paths'] ) as $p ) { $p = trim( $p ); if ( '' !== $p && 0 === strpos( $path, '/' . ltrim( $p, '/' ) ) ) { return true; } } return false; } /* --------------------------------------------------------------------- * Front end * ------------------------------------------------------------------- */ public function gate() { // Private preview link: remember this browser, then show the clean URL. // phpcs:disable WordPress.Security.NonceVerification -- the token is the check. if ( isset( $_GET['bylt_preview'] ) && $this->token() && hash_equals( $this->token(), sanitize_text_field( wp_unslash( $_GET['bylt_preview'] ) ) ) ) { setcookie( self::COOKIE, $this->cookie_value(), time() + WEEK_IN_SECONDS, COOKIEPATH ? COOKIEPATH : '/', COOKIE_DOMAIN, is_ssl(), true ); $_COOKIE[ self::COOKIE ] = $this->cookie_value(); wp_safe_redirect( remove_query_arg( 'bylt_preview' ) ); exit; } // Staff can look at the page while it's off (Settings โ†’ "See the page"). $peek = isset( $_GET['bylt_mm_peek'] ) && current_user_can( Bylt_Admin::cap() ); // phpcs:enable if ( ! $peek && ( ! $this->is_on() || $this->always_open() || $this->can_bypass() ) ) { return; } $this->render_page( $peek ); } private function render_page( $peek = false ) { $s = $this->settings(); $maint = 'maintenance' === $s['mode']; $end = $this->end_time(); $name = wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); $head = $s['headline'] ? $s['headline'] : ( $maint ? __( 'We\'ll be right back', 'byltcommerce-toolkit' ) : __( 'Coming soon', 'byltcommerce-toolkit' ) ); $msg = $s['message'] ? $s['message'] : ( $maint ? __( 'We\'re making some improvements. Please check back shortly.', 'byltcommerce-toolkit' ) : __( 'Our new site is almost ready. Check back soon.', 'byltcommerce-toolkit' ) ); nocache_headers(); if ( $maint && ! $peek ) { status_header( 503 ); header( 'Retry-After: ' . ( $end ? max( 60, $end - time() ) : HOUR_IN_SECONDS ) ); } else { status_header( 200 ); } if ( ( $maint || 'yes' === $s['noindex'] ) ) { header( 'X-Robots-Tag: noindex, nofollow' ); } header( 'Content-Type: text/html; charset=' . get_bloginfo( 'charset' ) ); $logo = $s['logo']; if ( ! $logo ) { // The theme's logo. $id = (int) get_theme_mod( 'custom_logo' ); $id = $id ? $id : (int) get_option( 'site_logo' ); $logo = $id ? (string) wp_get_attachment_image_url( $id, 'medium' ) : ''; } $bg = $s['bg_image'] ? 'background:' . $s['bg'] . ' url(' . esc_url( $s['bg_image'] ) . ') center/cover no-repeat fixed;' : 'background:' . $s['bg'] . ';'; // This page skips the theme, so its own styles and script are printed directly (registered the WordPress way). wp_register_style( 'bylt-maintenance', $this->url( 'assets/maintenance.css' ), array(), BYLT_VERSION ); wp_add_inline_style( 'bylt-maintenance', 'body{' . esc_html( $bg ) . 'color:' . esc_html( $s['text'] ) . '}.bylt-mm-contact a{color:' . esc_html( $s['accent'] ) . '}' ); wp_register_script( 'bylt-maintenance-countdown', $this->url( 'assets/countdown.js' ), array(), BYLT_VERSION, true ); ?> > <?php echo esc_html( $head . ' ยท ' . $name ); ?> '; } ?>
is_on() ? __( 'You\'re seeing the page visitors see.', 'byltcommerce-toolkit' ) : __( 'Preview: this page isn\'t switched on yet.', 'byltcommerce-toolkit' ) ); ?>

time() ) : ?>
0
0
0
0

time() ) { wp_print_scripts( 'bylt-maintenance-countdown' ); } ?> is_on() || ! current_user_can( Bylt_Admin::cap() ) ) { return; } $bar->add_node( array( 'id' => 'bylt-maintenance', 'title' => 'maintenance' === $this->settings()['mode'] ? __( 'Maintenance mode is on', 'byltcommerce-toolkit' ) : __( 'Coming soon mode is on', 'byltcommerce-toolkit' ), 'href' => Bylt_Admin::url( 'maintenance' ), 'meta' => array( 'class' => 'bylt-mm-bar' ), ) ); } public function admin_bar_css() { if ( $this->is_on() && is_admin_bar_showing() ) { wp_add_inline_style( 'admin-bar', '#wpadminbar .bylt-mm-bar > .ab-item{background:#b32d2e!important;color:#fff!important;font-weight:600}' ); } } /* --------------------------------------------------------------------- * Settings * ------------------------------------------------------------------- */ public function settings_tab( $tabs ) { $tabs['maintenance'] = __( 'Maintenance', 'byltcommerce-toolkit' ); return $tabs; } public function render_settings() { $s = $this->settings(); $roles = wp_roles()->get_names(); // phpcs:ignore WordPress.Security.NonceVerification if ( isset( $_GET['updated'] ) ) { echo '

' . esc_html__( 'Settings saved.', 'byltcommerce-toolkit' ) . '

'; } if ( $this->is_on() ) { echo '

' . esc_html( 'maintenance' === $s['mode'] ? __( 'Maintenance mode is on: visitors see the maintenance page.', 'byltcommerce-toolkit' ) : __( 'Coming soon mode is on: visitors see the coming soon page.', 'byltcommerce-toolkit' ) ) . '

'; } elseif ( 'yes' === $s['enabled'] && $this->end_time() ) { echo '

' . esc_html__( 'The end time has passed, so the site is open again. Clear or change the end time to switch it back on.', 'byltcommerce-toolkit' ) . '

'; } echo '
'; wp_nonce_field( 'bylt_maintenance_save' ); echo ''; echo ''; echo ''; echo ''; echo ''; echo '

' . esc_html__( 'The page', 'byltcommerce-toolkit' ) . '

'; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo '

' . esc_html__( 'See the page', 'byltcommerce-toolkit' ) . ' ' . esc_html__( 'Save first to see your changes.', 'byltcommerce-toolkit' ) . '

'; echo '

' . esc_html__( 'Who still sees the site', 'byltcommerce-toolkit' ) . '

'; echo ''; echo ''; /* translators: %s: visitor's IP */ echo ''; echo ''; echo ''; submit_button(); echo '
'; } private static function color( $v, $fallback ) { $v = sanitize_hex_color( (string) $v ); return $v ? $v : $fallback; } public function save_settings() { if ( ! current_user_can( Bylt_Admin::cap() ) ) { wp_die( esc_html__( 'You do not have permission to change these settings.', 'byltcommerce-toolkit' ), 403 ); } check_admin_referer( 'bylt_maintenance_save' ); $d = self::defaults(); $old = $this->settings(); // phpcs:disable WordPress.Security.NonceVerification -- checked above. $end = isset( $_POST['end'] ) ? sanitize_text_field( wp_unslash( $_POST['end'] ) ) : ''; $new = array( 'enabled' => empty( $_POST['enabled'] ) ? 'no' : 'yes', 'mode' => isset( $_POST['mode'] ) && 'maintenance' === $_POST['mode'] ? 'maintenance' : 'soon', 'headline' => isset( $_POST['headline'] ) ? sanitize_text_field( wp_unslash( $_POST['headline'] ) ) : '', 'message' => isset( $_POST['message'] ) ? wp_kses_post( wp_unslash( $_POST['message'] ) ) : '', 'logo' => isset( $_POST['logo'] ) ? esc_url_raw( wp_unslash( $_POST['logo'] ) ) : '', 'bg_image' => isset( $_POST['bg_image'] ) ? esc_url_raw( wp_unslash( $_POST['bg_image'] ) ) : '', 'bg' => self::color( isset( $_POST['bg'] ) ? wp_unslash( $_POST['bg'] ) : '', $d['bg'] ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- sanitize_hex_color(). 'text' => self::color( isset( $_POST['text'] ) ? wp_unslash( $_POST['text'] ) : '', $d['text'] ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized 'accent' => self::color( isset( $_POST['accent'] ) ? wp_unslash( $_POST['accent'] ) : '', $d['accent'] ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized 'end' => preg_match( '/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/', $end ) ? $end : '', 'countdown' => empty( $_POST['countdown'] ) ? 'no' : 'yes', 'contact' => isset( $_POST['contact'] ) ? sanitize_email( wp_unslash( $_POST['contact'] ) ) : '', 'staff_link' => empty( $_POST['staff_link'] ) ? 'no' : 'yes', 'noindex' => empty( $_POST['noindex'] ) ? 'no' : 'yes', 'roles' => isset( $_POST['roles'] ) ? array_values( array_unique( array_intersect( array_map( 'sanitize_key', (array) wp_unslash( $_POST['roles'] ) ), array_keys( wp_roles()->get_names() ) ) ) ) : array( 'administrator' ), 'ips' => isset( $_POST['ips'] ) ? implode( "\n", Bylt_Ip::parse_list( sanitize_textarea_field( wp_unslash( $_POST['ips'] ) ) ) ) : '', 'paths' => isset( $_POST['paths'] ) ? implode( "\n", array_filter( array_map( 'trim', array_map( 'sanitize_text_field', preg_split( '/\r\n|\r|\n/', (string) wp_unslash( $_POST['paths'] ) ) ) ) ) ) : '', // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- each line sanitized. 'token' => ! empty( $_POST['new_token'] ) || ! $old['token'] ? strtolower( wp_generate_password( 24, false ) ) : $old['token'], ); // phpcs:enable if ( ! in_array( 'administrator', $new['roles'], true ) ) { $new['roles'][] = 'administrator'; } update_option( self::OPTION, $new, false ); $this->settings = null; if ( $old['enabled'] !== $new['enabled'] || $old['mode'] !== $new['mode'] ) { Bylt_Cache::purge_all(); // Visitors must not get a cached copy of the other state. } $this->log( 'settings_changed', sprintf( 'Maintenance & Coming Soon saved: %1$s (%2$s)%3$s.', 'yes' === $new['enabled'] ? 'on' : 'off', $new['mode'], $new['end'] ? ', until ' . $new['end'] : '' ) ); wp_safe_redirect( Bylt_Admin::url( 'maintenance', array( 'updated' => 1 ) ) ); exit; } }