self::PAGE ), $args ), admin_url( 'options-general.php' ) ); } public static function app_url( $path = '' ) { return untrailingslashit( REPLYBASH_APP_URL ) . $path; } public static function menu() { add_options_page( __( 'ReplyBash', 'replybash' ), __( 'ReplyBash', 'replybash' ), 'manage_options', self::PAGE, array( __CLASS__, 'render' ) ); } public static function register() { register_setting( 'replybash', ReplyBash_Options::SETTINGS, array( 'type' => 'array', 'sanitize_callback' => array( 'ReplyBash_Options', 'sanitize' ), 'default' => ReplyBash_Options::defaults(), ) ); } public static function assets( $hook ) { if ( 'settings_page_' . self::PAGE === $hook ) { wp_enqueue_style( 'replybash-admin', plugins_url( 'assets/admin.css', REPLYBASH_FILE ), array(), REPLYBASH_VERSION ); } } public static function action_links( $links ) { array_unshift( $links, '' . esc_html__( 'Settings', 'replybash' ) . '' ); return $links; } // Right after activation (and until connected) the Plugins screen points to the settings page. public static function setup_notice() { $screen = get_current_screen(); if ( ! $screen || 'plugins' !== $screen->id || ! current_user_can( 'manage_options' ) || ReplyBash_Options::connection()['key'] ) { return; } printf( '

%s %s

', esc_html__( 'ReplyBash is almost ready: connect your agent to show the chat on your site.', 'replybash' ), esc_url( self::page_url() ), esc_html__( 'Connect now', 'replybash' ) ); } private static function check( $nonce_action ) { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You are not allowed to change these settings.', 'replybash' ), 403 ); } check_admin_referer( $nonce_action ); } private static function back( $notice ) { wp_safe_redirect( self::page_url( array( 'replybash_notice' => $notice ) ) ); exit; } public static function start_connect() { self::check( 'replybash_connect' ); $state = wp_generate_password( 32, false, false ); set_transient( 'replybash_state_' . get_current_user_id(), $state, self::STATE_TTL ); $url = add_query_arg( array( 'site' => rawurlencode( home_url() ), 'return' => rawurlencode( self::page_url() ), 'state' => $state, ), self::app_url( '/connect/wordpress' ) ); // The app is on another host; allow just that one for this redirect. $host = wp_parse_url( REPLYBASH_APP_URL, PHP_URL_HOST ); add_filter( 'allowed_redirect_hosts', function ( $hosts ) use ( $host ) { $hosts[] = $host; return $hosts; } ); wp_safe_redirect( $url ); exit; } // The app's redirect back: ?page=replybash&replybash_key=…&replybash_state=… public static function finish_connect() { // phpcs:disable WordPress.Security.NonceVerification.Recommended -- the state below is this flow's nonce. if ( ! isset( $_GET['page'], $_GET['replybash_state'] ) || self::PAGE !== $_GET['page'] ) { return; } if ( ! current_user_can( 'manage_options' ) ) { return; } $transient = 'replybash_state_' . get_current_user_id(); $expected = get_transient( $transient ); $state = sanitize_text_field( wp_unslash( $_GET['replybash_state'] ) ); $key = ReplyBash_Options::clean_key( isset( $_GET['replybash_key'] ) ? sanitize_text_field( wp_unslash( $_GET['replybash_key'] ) ) : '' ); $agent = isset( $_GET['replybash_agent'] ) ? sanitize_text_field( wp_unslash( $_GET['replybash_agent'] ) ) : ''; $workspace = isset( $_GET['replybash_workspace'] ) ? sanitize_text_field( wp_unslash( $_GET['replybash_workspace'] ) ) : ''; // phpcs:enable if ( ! is_string( $expected ) || ! hash_equals( $expected, $state ) || '' === $key ) { self::back( 'bad_state' ); } delete_transient( $transient ); ReplyBash_Options::connect( $key, $agent, $workspace ); self::back( 'connected' ); } public static function save_manual_key() { self::check( 'replybash_manual_key' ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- check() above verified the nonce. $key = ReplyBash_Options::clean_key( isset( $_POST['replybash_key'] ) ? sanitize_text_field( wp_unslash( $_POST['replybash_key'] ) ) : '' ); if ( '' === $key ) { self::back( 'bad_key' ); } ReplyBash_Options::connect( $key ); self::back( 'key_saved' ); } public static function disconnect() { self::check( 'replybash_disconnect' ); ReplyBash_Options::disconnect(); self::back( 'disconnected' ); } private static function notice() { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- only picks a message to show. $code = isset( $_GET['replybash_notice'] ) ? sanitize_key( $_GET['replybash_notice'] ) : ''; $messages = array( 'connected' => array( 'success', __( 'Connected. The chat now shows on your site.', 'replybash' ) ), 'key_saved' => array( 'success', __( 'Key saved. If the chat doesn\'t show, add this site\'s domain under Embed › Allowed domains in ReplyBash.', 'replybash' ) ), 'disconnected' => array( 'info', __( 'Disconnected. The chat no longer shows on your site.', 'replybash' ) ), 'bad_key' => array( 'error', __( 'That doesn\'t look like an agent key. Copy it from Embed in ReplyBash (it looks like acme_7Hq2k).', 'replybash' ) ), 'bad_state' => array( 'error', __( 'That connection link has expired or was meant for another admin. Click Connect again.', 'replybash' ) ), ); if ( isset( $messages[ $code ] ) ) { printf( '

%s

', esc_attr( $messages[ $code ][0] ), esc_html( $messages[ $code ][1] ) ); } } private static function post_form( $action, $button, $class = 'button' ) { ?>

' . esc_html__( 'Create one free', 'replybash' ) . '' ); ?>

·