__( 'Off (site is live)', 'sitehold' ), 'coming_soon' => __( 'Coming Soon', 'sitehold' ), 'maintenance' => __( 'Maintenance', 'sitehold' ), ); } public static function settings_url( $tab = '' ) { return admin_url( 'options-general.php?page=' . self::PAGE ) . ( $tab ? '#' . $tab : '' ); } public static function mode_url( $mode ) { return wp_nonce_url( admin_url( 'admin-post.php?action=sitehold_set_mode&mode=' . $mode ), 'sitehold_set_mode' ); } /* --------------------------------------------------------------------- * Menu, assets * ------------------------------------------------------------------ */ public static function menu() { add_options_page( __( 'SiteHold – Coming Soon & Maintenance', 'sitehold' ), __( 'SiteHold', 'sitehold' ), 'manage_options', self::PAGE, array( __CLASS__, 'render_page' ) ); } public static function assets( $hook ) { if ( 'settings_page_' . self::PAGE !== $hook ) { return; } wp_enqueue_media(); wp_enqueue_style( 'wp-color-picker' ); wp_enqueue_style( 'sitehold-admin', SITEHOLD_URL . 'assets/admin.css', array(), SITEHOLD_VERSION ); wp_enqueue_script( 'sitehold-admin', SITEHOLD_URL . 'assets/admin.js', array( 'jquery', 'wp-color-picker' ), SITEHOLD_VERSION, true ); wp_localize_script( 'sitehold-admin', 'SiteHoldAdmin', array( 'choose' => __( 'Choose image', 'sitehold' ), 'use' => __( 'Use this image', 'sitehold' ), 'copied' => __( 'Copied!', 'sitehold' ), ) ); } public static function action_links( $links ) { array_unshift( $links, '' . esc_html__( 'Settings', 'sitehold' ) . '' ); return $links; } /* --------------------------------------------------------------------- * Admin bar toggle * ------------------------------------------------------------------ */ public static function admin_bar( $bar ) { if ( ! current_user_can( 'manage_options' ) ) { return; } $mode = SiteHold::get( 'mode' ); $labels = self::mode_labels(); $status = array( 'off' => __( 'Site Live', 'sitehold' ), 'coming_soon' => __( 'Coming Soon ON', 'sitehold' ), 'maintenance' => __( 'Maintenance ON', 'sitehold' ), ); $bar->add_node( array( 'id' => 'sitehold', 'title' => '' . esc_html( $status[ $mode ] ) . '', 'href' => self::settings_url(), 'meta' => array( 'class' => 'sitehold-ab sitehold-ab--' . $mode, 'title' => __( 'SiteHold: Coming Soon & Maintenance mode', 'sitehold' ), ), ) ); foreach ( $labels as $key => $label ) { if ( $key === $mode ) { /* translators: %s: mode name, e.g. Maintenance */ $text = 'off' === $key ? __( 'Site is live', 'sitehold' ) : sprintf( __( '%s (active)', 'sitehold' ), $label ); } else { /* translators: %s: mode name, e.g. Maintenance */ $text = 'off' === $key ? __( 'Turn off (go live)', 'sitehold' ) : sprintf( __( 'Enable %s', 'sitehold' ), $label ); } $bar->add_node( array( 'parent' => 'sitehold', 'id' => 'sitehold-mode-' . $key, 'title' => ( $key === $mode ? '✓ ' : '' ) . esc_html( $text ), 'href' => $key === $mode ? false : self::mode_url( $key ), 'meta' => array( 'class' => $key === $mode ? 'sitehold-current' : '' ), ) ); } $preview = 'maintenance' === $mode ? 'maintenance' : 'coming_soon'; $bar->add_node( array( 'parent' => 'sitehold', 'id' => 'sitehold-preview', 'title' => esc_html__( 'Preview page', 'sitehold' ), 'href' => add_query_arg( 'sitehold_preview', $preview, home_url( '/' ) ), 'meta' => array( 'target' => '_blank' ), ) ); $bar->add_node( array( 'parent' => 'sitehold', 'id' => 'sitehold-settings', 'title' => esc_html__( 'Settings', 'sitehold' ), 'href' => self::settings_url(), ) ); } public static function admin_bar_css() { if ( ! is_admin_bar_showing() || ! current_user_can( 'manage_options' ) ) { return; } $css = ' #wpadminbar .sitehold-ab > .ab-item{display:flex!important;align-items:center;gap:6px} #wpadminbar .sitehold-dot{display:inline-block;width:9px;height:9px;border-radius:50%;background:#22c55e;box-shadow:0 0 0 2px rgba(255,255,255,.15)} #wpadminbar .sitehold-ab--coming_soon > .ab-item{background:#4f46e5!important;color:#fff!important} #wpadminbar .sitehold-ab--maintenance > .ab-item{background:#dc2626!important;color:#fff!important} #wpadminbar .sitehold-ab--coming_soon .sitehold-dot,#wpadminbar .sitehold-ab--maintenance .sitehold-dot{background:#fff;animation:siteholdPulse 1.6s infinite} #wpadminbar .sitehold-current > .ab-item{font-weight:600;opacity:.75} @keyframes siteholdPulse{50%{opacity:.35}} @media screen and (max-width:782px){#wpadminbar li#wp-admin-bar-sitehold{display:block}#wpadminbar .sitehold-ab > .ab-item{padding:0 8px!important}#wpadminbar .sitehold-label{display:none}#wpadminbar .sitehold-dot{width:14px;height:14px;margin-top:16px}}'; wp_add_inline_style( 'admin-bar', $css ); } public static function handle_set_mode() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You are not allowed to do this.', 'sitehold' ), 403 ); } check_admin_referer( 'sitehold_set_mode' ); $mode = isset( $_GET['mode'] ) ? sanitize_key( wp_unslash( $_GET['mode'] ) ) : ''; SiteHold::set_mode( $mode ); $back = wp_get_referer(); wp_safe_redirect( $back ? $back : self::settings_url() ); exit; } public static function notice() { if ( ! current_user_can( 'manage_options' ) || ! SiteHold::is_active() ) { return; } $mode = SiteHold::get( 'mode' ); $name = 'maintenance' === $mode ? __( 'Maintenance mode', 'sitehold' ) : __( 'Coming Soon mode', 'sitehold' ); printf( '

SiteHold: %1$s %3$s · %5$s

', /* translators: %s: mode name */ esc_html( sprintf( __( '%s is active — visitors cannot see your site.', 'sitehold' ), $name ) ), esc_url( self::mode_url( 'off' ) ), esc_html__( 'Turn off', 'sitehold' ), esc_url( self::settings_url() ), esc_html__( 'Settings', 'sitehold' ) ); } /* --------------------------------------------------------------------- * Settings * ------------------------------------------------------------------ */ public static function register() { register_setting( 'sitehold_group', SiteHold::OPTION, array( 'type' => 'array', 'sanitize_callback' => array( __CLASS__, 'sanitize' ), ) ); } public static function sanitize( $in ) { $in = is_array( $in ) ? $in : array(); $d = SiteHold::defaults(); $out = array(); $out['mode'] = isset( $in['mode'] ) && in_array( $in['mode'], SiteHold::MODES, true ) ? $in['mode'] : 'off'; foreach ( array( 'cs_headline', 'mt_headline', 'meta_title', 'launch_date' ) as $k ) { $out[ $k ] = isset( $in[ $k ] ) ? sanitize_text_field( $in[ $k ] ) : ''; } foreach ( array( 'cs_message', 'mt_message' ) as $k ) { $out[ $k ] = isset( $in[ $k ] ) ? wp_kses_post( $in[ $k ] ) : ''; } foreach ( array( 'meta_description', 'allowed_ips', 'excluded_paths' ) as $k ) { $out[ $k ] = isset( $in[ $k ] ) ? sanitize_textarea_field( $in[ $k ] ) : ''; } foreach ( array( 'show_login_link', 'countdown_enabled', 'auto_disable', 'block_rest', 'noindex' ) as $k ) { $out[ $k ] = empty( $in[ $k ] ) ? 0 : 1; } foreach ( array( 'logo_id', 'bg_image_id' ) as $k ) { $out[ $k ] = isset( $in[ $k ] ) ? absint( $in[ $k ] ) : 0; } foreach ( array( 'bg_color', 'text_color', 'accent_color' ) as $k ) { $color = isset( $in[ $k ] ) ? sanitize_hex_color( $in[ $k ] ) : ''; $out[ $k ] = $color ? $color : $d[ $k ]; } foreach ( array( 'social_facebook', 'social_x', 'social_instagram', 'social_linkedin', 'social_youtube' ) as $k ) { $out[ $k ] = isset( $in[ $k ] ) ? esc_url_raw( $in[ $k ] ) : ''; } $out['contact_email'] = isset( $in['contact_email'] ) ? sanitize_email( $in['contact_email'] ) : ''; $out['overlay'] = isset( $in['overlay'] ) ? min( 100, max( 0, (int) $in['overlay'] ) ) : $d['overlay']; $out['bypass_days'] = isset( $in['bypass_days'] ) ? min( 365, max( 1, (int) $in['bypass_days'] ) ) : $d['bypass_days']; $out['retry_after'] = isset( $in['retry_after'] ) ? min( 168, max( 1, (int) $in['retry_after'] ) ) : $d['retry_after']; $roles = array_keys( wp_roles()->get_names() ); $out['bypass_roles'] = isset( $in['bypass_roles'] ) ? array_values( array_intersect( (array) $in['bypass_roles'], $roles ) ) : array(); $key = isset( $in['bypass_key'] ) ? sanitize_key( $in['bypass_key'] ) : ''; $out['bypass_key'] = $key ? $key : SiteHold::generate_key(); return $out; } /* --------------------------------------------------------------------- * Field helpers * ------------------------------------------------------------------ */ private static function name( $key ) { return SiteHold::OPTION . '[' . $key . ']'; } private static function text( $s, $key, $type = 'text', $placeholder = '' ) { printf( '', esc_attr( $type ), esc_attr( $key ), esc_attr( self::name( $key ) ), esc_attr( $s[ $key ] ), esc_attr( $placeholder ) ); } private static function textarea( $s, $key, $rows = 4, $placeholder = '', $class = 'large-text' ) { printf( '', esc_attr( $class ), (int) $rows, esc_attr( $key ), esc_attr( self::name( $key ) ), esc_attr( $placeholder ), esc_textarea( $s[ $key ] ) ); } private static function checkbox( $s, $key, $label ) { printf( '', esc_attr( self::name( $key ) ), checked( 1, (int) $s[ $key ], false ), esc_html( $label ) ); } private static function color( $s, $key ) { printf( '', esc_attr( self::name( $key ) ), esc_attr( $s[ $key ] ), esc_attr( SiteHold::defaults()[ $key ] ) ); } private static function media( $s, $key ) { $id = (int) $s[ $key ]; $url = $id ? wp_get_attachment_image_url( $id, 'medium' ) : ''; ?>
__( 'General', 'sitehold' ), 'content' => __( 'Content', 'sitehold' ), 'design' => __( 'Design', 'sitehold' ), 'access' => __( 'Access', 'sitehold' ), 'seo' => __( 'SEO & Advanced', 'sitehold' ), ); $mode_desc = array( 'off' => __( 'Everyone sees your normal website.', 'sitehold' ), 'coming_soon' => __( 'For new sites. Returns HTTP 200 so the page can be shared.', 'sitehold' ), 'maintenance' => __( 'For temporary downtime. Returns HTTP 503 so search engines come back later.', 'sitehold' ), ); $bypass_url = add_query_arg( 'sitehold_bypass', $s['bypass_key'], home_url( '/' ) ); $my_ip = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : ''; ?>

$label ) : ?>