0, 'enabled' => 0, 'key' => '', 'subdomain' => '', 'host' => '', 'display_name' => '', 'ready' => 0, // App 內建瀏覽器警示(LINE/FB/IG)開關;與智能秘書連線狀態無關。 'inapp_warning' => 1, ); } function aiel_ec_get_options() { $opts = get_option( AIEL_EC_OPTION, array() ); if ( ! is_array( $opts ) ) { $opts = array(); } return wp_parse_args( $opts, aiel_ec_defaults() ); } /* ------------------------------------------------------------------------- * 前台注入(已連線且啟用時) * ---------------------------------------------------------------------- */ add_action( 'wp_enqueue_scripts', 'aiel_ec_enqueue_script' ); function aiel_ec_enqueue_script() { $o = aiel_ec_get_options(); if ( empty( $o['connected'] ) || empty( $o['enabled'] ) ) { return; } $host = preg_replace( '/[^a-z0-9.\-]/i', '', (string) $o['host'] ); $sub = preg_replace( '/[^a-z0-9\-]/i', '', (string) $o['subdomain'] ); if ( '' === $host || '' === $sub ) { return; } $src = sprintf( 'https://%s/embed/%s.js', $host, $sub ); // $ver=null 不帶 ?ver(泡泡永遠載最新);WP 6.3+ 以 strategy 非同步載入, // 舊版 WP 把陣列當 truthy $in_footer 處理(相容降級為 footer 同步載入)。 // 注意 phpcs:ignore 必須貼在 null 那一行——它只作用於「下一行」, // 放在函式呼叫前面不會蓋到報在 $ver 引數上的那筆。 wp_enqueue_script( 'aiel-smart-assistant', $src, array(), null, // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion -- remote SaaS script, intentionally unversioned so sites always load the latest embed. array( 'in_footer' => true, 'strategy' => 'async', ) ); } /* ------------------------------------------------------------------------- * 前台注入:App 內建瀏覽器(LINE / Facebook / Instagram)警告。 * 這些 App 的內建瀏覽器會擋 Google/第三方登入,導致會員登入失敗。偵測到就 * 提示改用 Chrome/Safari 開啟。與智能秘書是否連線無關;可於設定頁關閉 * (inapp_warning 選項,預設開啟)。 * wp_enqueue_scripts 只在前台觸發,所以這裡不需要(也不應該)再判斷 is_admin()。 * ---------------------------------------------------------------------- */ add_action( 'wp_enqueue_scripts', 'aiel_ec_enqueue_inapp_warning' ); function aiel_ec_enqueue_inapp_warning() { $o = aiel_ec_get_options(); if ( empty( $o['inapp_warning'] ) ) { return; } wp_enqueue_script( 'aiel-smart-assistant-inapp-warning', plugins_url( 'assets/inapp-warning.js', __FILE__ ), array(), AIEL_EC_VERSION, // 用布林 $in_footer,而非 6.3 才有的 array( 'in_footer' => true ):本外掛 // 宣告 Requires at least 5.0,陣列在 6.3 以下不是支援的簽名(只是剛好 // truthy 才沒出錯)。上面 embed 那支要 strategy=async 才非用陣列不可, // 這支不需要,所以用最直接、各版本都正確的布林。 true ); // 畫面文字透過 wp_localize_script 傳給 JS,維持可翻譯(__()),而非寫死在 .js 檔內。 wp_localize_script( 'aiel-smart-assistant-inapp-warning', 'aielInappWarningL10n', array( 'heading' => __( '請用瀏覽器開啟本站', 'aiel-smart-assistant' ), 'body' => __( '你正在 App(LINE/Facebook 等)的內建瀏覽器中開啟,會員登入等功能可能無法正常運作。請改用 Chrome 或 Safari 開啟。', 'aiel-smart-assistant' ), 'openChrome' => __( '用 Chrome 開啟', 'aiel-smart-assistant' ), 'copyUrl' => __( '複製網址(貼到瀏覽器)', 'aiel-smart-assistant' ), 'copied' => __( '已複製 ✓', 'aiel-smart-assistant' ), 'continue' => __( '繼續在此瀏覽', 'aiel-smart-assistant' ), ) ); } /* ------------------------------------------------------------------------- * 後台設定頁 * ---------------------------------------------------------------------- */ // 設定頁的 hook suffix 由 add_options_page() 回傳值決定(勿用猜的), // admin_menu 早於 admin_enqueue_scripts 執行,先存起來供後面比對。 $GLOBALS['aiel_ec_settings_hook'] = null; add_action( 'admin_menu', 'aiel_ec_admin_menu' ); function aiel_ec_admin_menu() { $GLOBALS['aiel_ec_settings_hook'] = add_options_page( __( '智能秘書', 'aiel-smart-assistant' ), __( '智能秘書', 'aiel-smart-assistant' ), 'manage_options', 'aiel-smart-assistant', 'aiel_ec_settings_page' ); } add_action( 'admin_enqueue_scripts', 'aiel_ec_admin_enqueue_styles' ); function aiel_ec_admin_enqueue_styles( $hook_suffix ) { // 只在本外掛自己的設定頁載入,不要對每個後台畫面都掛樣式表。 if ( $hook_suffix !== $GLOBALS['aiel_ec_settings_hook'] ) { return; } wp_enqueue_style( 'aiel-smart-assistant-admin', plugins_url( 'assets/admin.css', __FILE__ ), array(), AIEL_EC_VERSION ); } function aiel_ec_settings_url( $args = array() ) { return add_query_arg( array_merge( array( 'page' => 'aiel-smart-assistant' ), $args ), admin_url( 'options-general.php' ) ); } /* ---- 動作:連線 ---- */ add_action( 'admin_post_aiel_ec_connect', 'aiel_ec_handle_connect' ); function aiel_ec_handle_connect() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( 'forbidden' ); } check_admin_referer( 'aiel_ec_connect' ); $key = isset( $_POST['aiel_ec_key'] ) ? trim( sanitize_text_field( wp_unslash( $_POST['aiel_ec_key'] ) ) ) : ''; if ( '' === $key ) { wp_safe_redirect( aiel_ec_settings_url( array( 'err' => 'empty' ) ) ); exit; } $res = wp_remote_post( aiel_ec_platform_base() . '/api/embed-chat/connect', array( 'timeout' => 15, 'headers' => array( 'X-AIEL-Key' => $key, 'Content-Type' => 'application/json', ), 'body' => '{}', ) ); if ( is_wp_error( $res ) ) { wp_safe_redirect( aiel_ec_settings_url( array( 'err' => 'network' ) ) ); exit; } $code = wp_remote_retrieve_response_code( $res ); $data = json_decode( wp_remote_retrieve_body( $res ), true ); if ( 200 !== (int) $code || empty( $data['ok'] ) ) { $err = is_array( $data ) && isset( $data['error'] ) ? $data['error'] : 'failed'; wp_safe_redirect( aiel_ec_settings_url( array( 'err' => $err ) ) ); exit; } $o = aiel_ec_get_options(); $o['connected'] = 1; $o['enabled'] = 1; // 連線後預設啟用 $o['key'] = $key; $o['subdomain'] = isset( $data['subdomain'] ) ? sanitize_text_field( $data['subdomain'] ) : ''; $o['host'] = isset( $data['host'] ) ? sanitize_text_field( $data['host'] ) : ''; $o['display_name'] = isset( $data['displayName'] ) ? sanitize_text_field( $data['displayName'] ) : ''; $o['ready'] = ! empty( $data['ready'] ) ? 1 : 0; update_option( AIEL_EC_OPTION, $o ); wp_safe_redirect( aiel_ec_settings_url( array( 'ok' => 'connected' ) ) ); exit; } /* ---- 動作:中斷連線 ---- */ add_action( 'admin_post_aiel_ec_disconnect', 'aiel_ec_handle_disconnect' ); function aiel_ec_handle_disconnect() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( 'forbidden' ); } check_admin_referer( 'aiel_ec_disconnect' ); update_option( AIEL_EC_OPTION, aiel_ec_defaults() ); wp_safe_redirect( aiel_ec_settings_url( array( 'ok' => 'disconnected' ) ) ); exit; } /* ---- 動作:切換啟用 ---- */ add_action( 'admin_post_aiel_ec_toggle', 'aiel_ec_handle_toggle' ); function aiel_ec_handle_toggle() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( 'forbidden' ); } check_admin_referer( 'aiel_ec_toggle' ); $o = aiel_ec_get_options(); // 泡泡開關只在已連線時有意義(未連線的表單不含此欄位,避免誤清)。 if ( ! empty( $o['connected'] ) ) { $o['enabled'] = ! empty( $_POST['aiel_ec_enabled'] ) ? 1 : 0; } $o['inapp_warning'] = ! empty( $_POST['aiel_ec_inapp_warning'] ) ? 1 : 0; update_option( AIEL_EC_OPTION, $o ); wp_safe_redirect( aiel_ec_settings_url( array( 'ok' => 'saved' ) ) ); exit; } function aiel_ec_settings_page() { if ( ! current_user_can( 'manage_options' ) ) { return; } $o = aiel_ec_get_options(); $errs = array( 'empty' => '請先貼上連線金鑰。', 'network' => '連線失敗,請稍後再試。', 'invalid_key' => '金鑰無效或已撤銷。', 'missing_key' => '未收到金鑰。', 'not_embed_chat' => '這不是智能秘書工作區。', 'workspace_unavailable' => '工作區目前無法使用。', 'rate_limited' => '嘗試太頻繁,請稍後再試。', 'failed' => '連線失敗。', ); // phpcs:disable WordPress.Security.NonceVerification.Recommended -- display-only // feedback codes set by our own wp_safe_redirect above; no state is changed here. $err = isset( $_GET['err'] ) ? sanitize_text_field( wp_unslash( $_GET['err'] ) ) : ''; $ok = isset( $_GET['ok'] ) ? sanitize_text_field( wp_unslash( $_GET['ok'] ) ) : ''; // phpcs:enable WordPress.Security.NonceVerification.Recommended ?>


()


' . esc_html__( '設定', 'aiel-smart-assistant' ) . ''; array_unshift( $links, $settings ); return $links; }