self::ACTION, 'redirect' => rawurlencode( $redirect ), ), admin_url( 'admin-post.php' ) ), self::ACTION ); } /** * Toggles via admin-post.php (works without JavaScript). * * @since 0.1.0 * * @return void */ public function handle_toggle() { if ( ! self::is_available() ) { wp_die( esc_html__( 'This action is not allowed.', 'oms-quietadmin' ), 403 ); } check_admin_referer( self::ACTION ); $active = ClientMode::toggle_ghost_mode(); Tracker::log( Event_Log::TYPE_AGENCY, $active ? 'ghost_mode_on' : 'ghost_mode_off', $active ? __( 'Ghost Mode enabled (client preview)', 'oms-quietadmin' ) : __( 'Ghost Mode disabled', 'oms-quietadmin' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce was verified above via check_admin_referer(). $redirect = isset( $_GET['redirect'] ) ? esc_url_raw( wp_unslash( $_GET['redirect'] ) ) : ''; // wp_validate_redirect() only allows targets on this site. $redirect = '' !== $redirect ? wp_validate_redirect( $redirect, admin_url() ) : admin_url(); wp_safe_redirect( $redirect ); exit; } /** * AJAX variant (keyboard shortcut in the admin area). * * @since 0.1.0 * * @return void */ public function handle_ajax_toggle() { check_ajax_referer( self::ACTION, 'nonce' ); if ( ! self::is_available() ) { wp_send_json_error( array( 'message' => __( 'Not allowed.', 'oms-quietadmin' ) ), 403 ); } $active = ClientMode::toggle_ghost_mode(); wp_send_json_success( array( 'active' => $active, 'reload' => true, 'message' => $active ? __( 'Client view active – this is how your client sees the backend.', 'oms-quietadmin' ) : __( 'Agency view restored.', 'oms-quietadmin' ), ) ); } /** * Admin bar toggle. * * @since 0.1.0 * * @param \WP_Admin_Bar $wp_admin_bar Admin bar. * @return void */ public function admin_bar_node( $wp_admin_bar ) { if ( ! is_user_logged_in() ) { return; } if ( ! self::is_available() ) { return; } $active = ClientMode::is_ghost_mode(); $wp_admin_bar->add_node( array( 'id' => 'quietadmin-ghost', 'parent' => 'top-secondary', 'title' => '' . ( $active ? esc_html__( 'Ghost Mode: ON', 'oms-quietadmin' ) : esc_html__( 'Preview client view', 'oms-quietadmin' ) ), 'href' => self::toggle_url(), 'meta' => array( 'title' => $active ? __( 'Back to the full agency view (shortcut: Alt+Q)', 'oms-quietadmin' ) : __( 'Simulate the client view without switching accounts (shortcut: Alt+Q)', 'oms-quietadmin' ), 'class' => $active ? 'qa-ghost-active' : '', ), ) ); } /** * Banner in the admin area while the preview is running. * * @since 0.1.0 * * @return void */ public function render_banner() { if ( ! ClientMode::is_active() || ! self::is_available() ) { return; } if ( ! ClientMode::is_ghost_mode() ) { return; } Template::render( 'ghost-banner', array( 'toggle_url' => self::toggle_url(), ) ); } /** * Always show the admin bar in Ghost Mode (otherwise switching back is impossible). * * @since 0.1.0 * * @param bool $show Previous value. * @return bool */ public function force_admin_bar( $show ) { if ( self::is_available() && ClientMode::is_ghost_mode() ) { return true; } return $show; } /** * Current URL (for the redirect after toggling). * * @since 0.1.0 * * @return string */ protected static function current_url() { if ( ! isset( $_SERVER['REQUEST_URI'] ) ) { return admin_url(); } $uri = esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ); // Build the origin from the site URL instead of the (spoofable) Host header. $parts = wp_parse_url( home_url() ); if ( empty( $parts['scheme'] ) || empty( $parts['host'] ) ) { return admin_url(); } $origin = $parts['scheme'] . '://' . $parts['host'] . ( isset( $parts['port'] ) ? ':' . $parts['port'] : '' ); return $origin . '/' . ltrim( $uri, '/' ); } }