文章目录
-
- 在当今全球化的互联网环境中,多语言支持已成为网站建设的标配功能。对于WordPress这一占据全球43%网站市场的开源平台而言,通过插件扩展其多语言功能具有巨大的实用价值和商业潜力。本教程将深入讲解如何开发一个集成了实时翻译聊天与多语言客服工具的WordPress插件,通过代码二次开发实现这一实用功能。 WordPress插件开发不仅能够满足特定业务需求,还能为开发者带来可观的收益。根据WordPress官方数据,插件目录中已有超过5.8万个免费插件,而高级插件市场更是价值数十亿美元。掌握插件开发技能,意味着您可以为全球数百万WordPress网站提供解决方案。
-
- 在开始插件开发前,我们需要搭建合适的开发环境: 本地开发环境:推荐使用XAMPP、MAMP或Local by Flywheel,它们提供了完整的PHP、MySQL和Apache/Nginx环境。 代码编辑器:Visual Studio Code、PHPStorm或Sublime Text都是优秀的选择,确保安装PHP智能提示和WordPress代码片段插件。 WordPress安装:下载最新版WordPress并安装在本地环境中,建议使用调试模式,在wp-config.php中添加: define('WP_DEBUG', true); define('WP_DEBUG_LOG', true); define('WP_DEBUG_DISPLAY', false);
- 创建一个标准的WordPress插件需要遵循特定的目录结构和文件组织: multilingual-chat-support/ │ ├── multilingual-chat-support.php # 主插件文件 ├── uninstall.php # 卸载脚本 ├── readme.txt # 插件说明 ├── assets/ # 静态资源 │ ├── css/ │ ├── js/ │ └── images/ ├── includes/ # 包含文件 │ ├── class-chat-handler.php │ ├── class-translation-api.php │ └── class-admin-settings.php ├── languages/ # 国际化文件 ├── templates/ # 前端模板 └── vendor/ # 第三方库(如果需要)
- 主插件文件是插件的入口点,需要包含标准的插件头部信息: <?php /** * Plugin Name: 多语言实时聊天与客服工具 * Plugin URI: https://yourwebsite.com/multilingual-chat * Description: 为WordPress网站添加实时翻译聊天和多语言客服功能 * Version: 1.0.0 * Author: 您的名称 * Author URI: https://yourwebsite.com * License: GPL v2 or later * Text Domain: multilingual-chat * Domain Path: /languages */ // 防止直接访问 if (!defined('ABSPATH')) { exit; } // 定义插件常量 define('MCS_VERSION', '1.0.0'); define('MCS_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('MCS_PLUGIN_URL', plugin_dir_url(__FILE__)); define('MCS_PLUGIN_BASENAME', plugin_basename(__FILE__)); // 初始化插件 require_once MCS_PLUGIN_DIR . 'includes/class-plugin-init.php'; $mcs_plugin = new MCS_Plugin_Init(); $mcs_plugin->run();
-
- 实时翻译是插件的核心功能之一。我们可以选择多种翻译API: Google Cloud Translation API:准确度高,支持100多种语言 Microsoft Azure Translator:性价比优秀,有免费额度 DeepL API:欧洲语言翻译质量极高 百度翻译API:中文翻译效果优秀 以下是如何集成Google翻译API的示例: <?php class MCS_Translation_API { private $api_key; private $api_url = 'https://translation.googleapis.com/language/translate/v2'; public function __construct($api_key) { $this->api_key = $api_key; } /** * 翻译文本 * @param string $text 要翻译的文本 * @param string $target_lang 目标语言代码 * @param string $source_lang 源语言代码(可选,自动检测) * @return array 翻译结果 */ public function translate($text, $target_lang, $source_lang = null) { $args = array( 'key' => $this->api_key, 'q' => $text, 'target' => $target_lang, 'format' => 'text' ); if ($source_lang) { $args['source'] = $source_lang; } $url = add_query_arg($args, $this->api_url); $response = wp_remote_get($url, array( 'timeout' => 15, 'headers' => array( 'Content-Type' => 'application/json', ) )); if (is_wp_error($response)) { return array( 'success' => false, 'error' => $response->get_error_message() ); } $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); if (isset($data['error'])) { return array( 'success' => false, 'error' => $data['error']['message'] ); } return array( 'success' => true, 'translatedText' => $data['data']['translations'][0]['translatedText'], 'detectedSourceLanguage' => $data['data']['translations'][0]['detectedSourceLanguage'] ); } /** * 批量翻译 */ public function translate_batch($texts, $target_lang, $source_lang = null) { // 实现批量翻译逻辑 } /** * 获取支持的语言列表 */ public function get_supported_languages() { $url = 'https://translation.googleapis.com/language/translate/v2/languages'; $url = add_query_arg(array( 'key' => $this->api_key, 'target' => 'zh-CN' ), $url); // 发送请求并处理响应 } }
- 为了减少API调用次数和提高响应速度,我们需要实现翻译缓存: class MCS_Translation_Cache { private $cache_table; public function __construct() { global $wpdb; $this->cache_table = $wpdb->prefix . 'mcs_translation_cache'; } /** * 创建缓存表 */ public function create_table() { global $wpdb; $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE IF NOT EXISTS {$this->cache_table} ( id bigint(20) NOT NULL AUTO_INCREMENT, source_text text NOT NULL, source_lang varchar(10) DEFAULT '', target_lang varchar(10) NOT NULL, translated_text text NOT NULL, hash varchar(32) NOT NULL, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY hash (hash), KEY source_lang (source_lang), KEY target_lang (target_lang) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); } /** * 获取缓存翻译 */ public function get($text, $target_lang, $source_lang = '') { global $wpdb; $hash = md5($text . $source_lang . $target_lang); $result = $wpdb->get_row($wpdb->prepare( "SELECT translated_text FROM {$this->cache_table} WHERE hash = %s", $hash )); return $result ? $result->translated_text : false; } /** * 设置缓存 */ public function set($text, $translated_text, $target_lang, $source_lang = '') { global $wpdb; $hash = md5($text . $source_lang . $target_lang); $wpdb->insert( $this->cache_table, array( 'source_text' => $text, 'source_lang' => $source_lang, 'target_lang' => $target_lang, 'translated_text' => $translated_text, 'hash' => $hash ), array('%s', '%s', '%s', '%s', '%s') ); } /** * 清理旧缓存 */ public function cleanup($days_old = 30) { global $wpdb; $wpdb->query($wpdb->prepare( "DELETE FROM {$this->cache_table} WHERE created_at < DATE_SUB(NOW(), INTERVAL %d DAY)", $days_old )); } }
-
- 实时聊天需要双向通信,我们可以使用WebSocket技术: class MCS_WebSocket_Server { private $server; private $clients = []; private $translator; public function __construct($translator) { $this->translator = $translator; } /** * 启动WebSocket服务器 */ public function start($host = '0.0.0.0', $port = 8080) { $this->server = new SwooleWebSocketServer($host, $port); $this->server->on('open', function($server, $request) { $this->clients[$request->fd] = [ 'fd' => $request->fd, 'user_id' => 0, 'language' => 'en', 'room_id' => null ]; echo "客户端 {$request->fd} 已连接n"; }); $this->server->on('message', function($server, $frame) { $this->handle_message($frame->fd, $frame->data); }); $this->server->on('close', function($server, $fd) { unset($this->clients[$fd]); echo "客户端 {$fd} 已断开连接n"; }); $this->server->start(); } /** * 处理客户端消息 */ private function handle_message($fd, $data) { $message = json_decode($data, true); if (!$message || !isset($message['type'])) { return; } switch ($message['type']) { case 'auth': $this->handle_auth($fd, $message); break; case 'chat_message': $this->handle_chat_message($fd, $message); break; case 'join_room': $this->handle_join_room($fd, $message); break; case 'typing': $this->handle_typing($fd, $message); break; } } /** * 处理认证 */ private function handle_auth($fd, $message) { if (isset($message['user_id'], $message['language'])) { $this->clients[$fd]['user_id'] = intval($message['user_id']); $this->clients[$fd]['language'] = sanitize_text_field($message['language']); $this->send_to_client($fd, [ 'type' => 'auth_success', 'message' => '认证成功' ]); } } /** * 处理聊天消息 */ private function handle_chat_message($fd, $message) { if (!isset($message['content'], $message['room_id'])) { return; } $client = $this->clients[$fd]; $room_id = $message['room_id']; $original_content = sanitize_text_field($message['content']); // 保存消息到数据库 $message_id = $this->save_message_to_db( $client['user_id'], $room_id, $original_content, $client['language'] ); // 向房间内所有客户端发送消息(自动翻译) $this->broadcast_to_room($room_id, [ 'type' => 'new_message', 'message_id' => $message_id, 'sender_id' => $client['user_id'], 'original_content' => $original_content, 'original_language' => $client['language'], 'timestamp' => current_time('mysql') ], $fd); } /** * 向客户端发送消息 */ private function send_to_client($fd, $data) { if ($this->server->exist($fd)) { $this->server->push($fd, json_encode($data)); } } /** * 向房间广播消息 */ private function broadcast_to_room($room_id, $data, $exclude_fd = null) { foreach ($this->clients as $client) { if ($client['room_id'] == $room_id && $client['fd'] != $exclude_fd) { // 根据客户端语言翻译消息 if (isset($data['original_content'])) { $translation = $this->translator->translate( $data['original_content'], $client['language'], $data['original_language'] ); if ($translation['success']) { $data['translated_content'] = $translation['translatedText']; } } $this->send_to_client($client['fd'], $data); } } } }
- 创建响应式的前端聊天界面: class MCSChatWidget { constructor(options) { this.options = Object.assign({ position: 'bottom-right', primaryColor: '#0073aa', defaultLanguage: 'en', availableLanguages: ['en', 'zh-CN', 'es', 'fr', 'de', 'ja'], autoOpen: false, greetingMessage: '您好!需要什么帮助吗?' }, options); this.ws = null; this.isConnected = false; this.currentRoom = null; this.userLanguage = this.detectUserLanguage(); this.init(); } /** * 初始化聊天组件 */ init() { this.createWidgetHTML(); this.bindEvents(); this.loadUserSettings(); if (this.options.autoOpen) { setTimeout(() => this.openChat(), 1000); } } /** * 创建聊天界面HTML */ createWidgetHTML() { // 创建主容器 this.container = document.createElement('div'); this.container.className = 'mcs-chat-container'; this.container.style.cssText = ` position: fixed; z-index: 999999; ${this.getPositionStyles()} font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif; `; // 创建聊天按钮 this.chatButton = document.createElement('div'); this.chatButton.className = 'mcs-chat-button'; this.chatButton.innerHTML = ` <svg width="24" height="24" viewBox="0 0 24 24" fill="white"> <path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-2 12H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z"/> </svg> `; // 创建聊天窗口 this.chatWindow = document.createElement('div'); this.chatWindow.className = 'mcs-chat-window'; this.chatWindow.style.display = 'none'; this.chatWindow.innerHTML = ` <div class="mcs-chat-header"> <h3>${this.options.greetingMessage}</h3> <div class="mcs-header-actions"> <select class="mcs-language-selector"> ${this.options.availableLanguages.map(lang => `<option value="${lang}" ${lang === this.userLanguage ? 'selected' : ''}> ${this.getLanguageName(lang)} </option>` ).join('')} </select> <button class="mcs-close-chat">×</button> </div> </div> <div class="mcs-chat-messages"></div> <div class="mcs-chat-input-area"> <textarea class="mcs-message-input" placeholder="输入消息..."></textarea> <button class="mcs-send-button">发送</button> </div> `; this.container.appendChild(this.chatButton); this.container.appendChild(this.chatWindow); document.body.appendChild(this.container); this.addStyles(); } /** * 连接WebSocket服务器 */ connectWebSocket() { if (this.ws && this.isConnected) return; const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const wsUrl = `${protocol}//${window.location.hostname}:8080`; this.ws = new WebSocket(wsUrl); this.ws.onopen = () => { this.isConnected = true; this.authenticate(); this.showNotification('已连接到聊天服务器'); }; this.ws.onmessage = (event) => { this.handleWebSocketMessage(JSON.parse(event.data)); this.ws.onclose = () => { this.isConnected = false; this.showNotification('连接已断开,正在尝试重新连接...'); setTimeout(() => this.connectWebSocket(), 3000); }; this.ws.onerror = (error) => { console.error('WebSocket错误:', error); }; } /** * 处理WebSocket消息 */ handleWebSocketMessage(data) { switch (data.type) { case 'auth_success': this.handleAuthSuccess(data); break; case 'new_message': this.handleNewMessage(data); break; case 'typing_indicator': this.handleTypingIndicator(data); break; case 'room_joined': this.handleRoomJoined(data); break; case 'error': this.showNotification(data.message, 'error'); break; } } /** * 处理新消息 */ handleNewMessage(data) { const messagesContainer = this.chatWindow.querySelector('.mcs-chat-messages'); const messageElement = this.createMessageElement(data); messagesContainer.appendChild(messageElement); messagesContainer.scrollTop = messagesContainer.scrollHeight; // 显示桌面通知(如果用户不在当前标签页) if (document.hidden && this.options.desktopNotifications) { this.showDesktopNotification(data); } } /** * 创建消息元素 */ createMessageElement(data) { const messageDiv = document.createElement('div'); messageDiv.className = `mcs-message ${data.sender_id === this.userId ? 'own-message' : 'other-message'}`; const time = new Date(data.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); let content = ` <div class="mcs-message-content"> <div class="mcs-original-text">${this.escapeHtml(data.original_content)}</div> `; if (data.translated_content && data.translated_content !== data.original_content) { content += ` <div class="mcs-translated-text"> <small>翻译:</small> ${this.escapeHtml(data.translated_content)} </div> `; } content += ` <div class="mcs-message-time">${time}</div> </div> `; messageDiv.innerHTML = content; return messageDiv; } /** * 绑定事件 */ bindEvents() { // 聊天按钮点击事件 this.chatButton.addEventListener('click', () => this.toggleChat()); // 关闭按钮事件 this.chatWindow.querySelector('.mcs-close-chat').addEventListener('click', () => this.closeChat()); // 发送按钮事件 this.chatWindow.querySelector('.mcs-send-button').addEventListener('click', () => this.sendMessage()); // 输入框回车发送 this.chatWindow.querySelector('.mcs-message-input').addEventListener('keypress', (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); this.sendMessage(); } }); // 输入框输入事件(显示正在输入) this.chatWindow.querySelector('.mcs-message-input').addEventListener('input', (e) => { this.sendTypingIndicator(); }); // 语言选择器变更事件 this.chatWindow.querySelector('.mcs-language-selector').addEventListener('change', (e) => { this.userLanguage = e.target.value; this.saveUserSettings(); this.updateLanguage(); }); } /** * 发送消息 */ sendMessage() { const input = this.chatWindow.querySelector('.mcs-message-input'); const message = input.value.trim(); if (!message || !this.isConnected || !this.currentRoom) return; // 发送到WebSocket服务器 this.ws.send(JSON.stringify({ type: 'chat_message', room_id: this.currentRoom, content: message, language: this.userLanguage })); // 清空输入框 input.value = ''; input.focus(); } /** * 发送正在输入指示 */ sendTypingIndicator() { if (!this.isConnected || !this.currentRoom) return; this.ws.send(JSON.stringify({ type: 'typing', room_id: this.currentRoom, is_typing: true })); // 清除之前的定时器 if (this.typingTimeout) { clearTimeout(this.typingTimeout); } // 设置停止输入指示 this.typingTimeout = setTimeout(() => { if (this.isConnected) { this.ws.send(JSON.stringify({ type: 'typing', room_id: this.currentRoom, is_typing: false })); } }, 1000); } /** * 添加CSS样式 */ addStyles() { const style = document.createElement('style'); style.textContent = ` .mcs-chat-button { width: 60px; height: 60px; background-color: ${this.options.primaryColor}; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 2px 10px rgba(0,0,0,0.2); transition: all 0.3s ease; } .mcs-chat-button:hover { transform: scale(1.1); box-shadow: 0 4px 15px rgba(0,0,0,0.3); } .mcs-chat-window { width: 350px; height: 500px; background: white; border-radius: 10px; box-shadow: 0 5px 25px rgba(0,0,0,0.15); display: flex; flex-direction: column; overflow: hidden; } .mcs-chat-header { background: ${this.options.primaryColor}; color: white; padding: 15px; display: flex; justify-content: space-between; align-items: center; } .mcs-chat-header h3 { margin: 0; font-size: 16px; font-weight: 500; } .mcs-header-actions { display: flex; align-items: center; gap: 10px; } .mcs-language-selector { background: rgba(255,255,255,0.2); border: none; color: white; padding: 5px; border-radius: 4px; font-size: 12px; } .mcs-close-chat { background: none; border: none; color: white; font-size: 24px; cursor: pointer; line-height: 1; } .mcs-chat-messages { flex: 1; padding: 15px; overflow-y: auto; background: #f8f9fa; } .mcs-message { margin-bottom: 15px; max-width: 80%; } .mcs-message.own-message { margin-left: auto; } .mcs-message.other-message { margin-right: auto; } .mcs-message-content { background: white; padding: 10px 15px; border-radius: 18px; box-shadow: 0 1px 2px rgba(0,0,0,0.1); } .own-message .mcs-message-content { background: ${this.options.primaryColor}; color: white; border-bottom-right-radius: 4px; } .other-message .mcs-message-content { border-bottom-left-radius: 4px; } .mcs-translated-text { margin-top: 5px; padding-top: 5px; border-top: 1px dashed rgba(0,0,0,0.1); font-size: 0.9em; color: #666; } .own-message .mcs-translated-text { border-top-color: rgba(255,255,255,0.3); color: rgba(255,255,255,0.9); } .mcs-message-time { font-size: 11px; color: #999; margin-top: 5px; text-align: right; } .mcs-chat-input-area { border-top: 1px solid #e0e0e0; padding: 15px; background: white; } .mcs-message-input { width: 100%; border: 1px solid #ddd; border-radius: 20px; padding: 10px 15px; resize: none; font-family: inherit; font-size: 14px; min-height: 40px; max-height: 100px; box-sizing: border-box; } .mcs-message-input:focus { outline: none; border-color: ${this.options.primaryColor}; } .mcs-send-button { background: ${this.options.primaryColor}; color: white; border: none; border-radius: 20px; padding: 8px 20px; margin-top: 10px; cursor: pointer; font-weight: 500; float: right; } .mcs-send-button:hover { opacity: 0.9; } @media (max-width: 480px) { .mcs-chat-window { width: 100%; height: 100%; border-radius: 0; position: fixed; top: 0; left: 0; right: 0; bottom: 0; } } `; document.head.appendChild(style); } } ## 第四章:多语言客服工具集成 ### 4.1 客服工单系统 除了实时聊天,我们还需要一个完整的客服工单系统: class MCS_Support_Ticket_System { private $db; public function __construct() { global $wpdb; $this->db = $wpdb; } /** * 创建工单表 */ public function create_tables() { $charset_collate = $this->db->get_charset_collate(); $tickets_table = $this->db->prefix . 'mcs_support_tickets'; $tickets_sql = "CREATE TABLE IF NOT EXISTS $tickets_table ( id bigint(20) NOT NULL AUTO_INCREMENT, ticket_number varchar(50) NOT NULL, user_id bigint(20) NOT NULL, subject varchar(255) NOT NULL, description text NOT NULL, status varchar(50) DEFAULT 'open', priority varchar(50) DEFAULT 'medium', language varchar(10) NOT NULL, assigned_to bigint(20) DEFAULT 0, created_at datetime DEFAULT CURRENT_TIMESTAMP, updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY ticket_number (ticket_number), KEY user_id (user_id), KEY status (status), KEY assigned_to (assigned_to) ) $charset_collate;"; $replies_table = $this->db->prefix . 'mcs_ticket_replies'; $replies_sql = "CREATE TABLE IF NOT EXISTS $replies_table ( id bigint(20) NOT NULL AUTO_INCREMENT, ticket_id bigint(20) NOT NULL, user_id bigint(20) NOT NULL, message text NOT NULL, original_language varchar(10) NOT NULL, is_internal tinyint(1) DEFAULT 0, attachments text, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY ticket_id (ticket_id), KEY user_id (user_id) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($tickets_sql); dbDelta($replies_sql); } /** * 创建新工单 */ public function create_ticket($data) { $ticket_number = 'TICKET-' . date('Ymd') . '-' . strtoupper(wp_generate_password(6, false)); $result = $this->db->insert( $this->db->prefix . 'mcs_support_tickets', array( 'ticket_number' => $ticket_number, 'user_id' => $data['user_id'], 'subject' => sanitize_text_field($data['subject']), 'description' => wp_kses_post($data['description']), 'language' => sanitize_text_field($data['language']), 'priority' => $data['priority'] ?? 'medium', 'status' => 'open' ), array('%s', '%d', '%s', '%s', '%s', '%s', '%s') ); if ($result) { $ticket_id = $this->db->insert_id; // 发送通知邮件 $this->send_ticket_notification($ticket_id, 'created'); // 记录活动日志 $this->log_ticket_activity($ticket_id, 'ticket_created', $data['user_id']); return array( 'success' => true, 'ticket_id' => $ticket_id, 'ticket_number' => $ticket_number ); } return array( 'success' => false, 'error' => '创建工单失败' ); } /** * 添加工单回复 */ public function add_reply($ticket_id, $data) { $ticket = $this->get_ticket($ticket_id); if (!$ticket) { return array('success' => false, 'error' => '工单不存在'); } $result = $this->db->insert( $this->db->prefix . 'mcs_ticket_replies', array( 'ticket_id' => $ticket_id, 'user_id' => $data['user_id'], 'message' => wp_kses_post($data['message']), 'original_language' => $data['language'], 'is_internal' => $data['is_internal'] ?? 0 ), array('%d', '%d', '%s', '%s', '%d') ); if ($result) { // 更新工单状态 $this->update_ticket_status($ticket_id, $data['user_id']); // 发送通知 $this->send_ticket_notification($ticket_id, 'replied', $data['user_id']); // 自动翻译回复内容 $this->translate_ticket_reply($this->db->insert_id, $ticket['language']); return array('success' => true, 'reply_id' => $this->db->insert_id); } return array('success' => false, 'error' => '添加回复失败'); } /** * 自动翻译工单回复 */ private function translate_ticket_reply($reply_id, $target_language) { $reply = $this->db->get_row($this->db->prepare( "SELECT * FROM {$this->db->prefix}mcs_ticket_replies WHERE id = %d", $reply_id )); if ($reply && $reply->original_language !== $target_language) { $translation = $this->translate_content($reply->message, $target_language, $reply->original_language); if ($translation['success']) { // 保存翻译后的内容 update_comment_meta($reply_id, '_translated_message', $translation['translatedText']); update_comment_meta($reply_id, '_translation_language', $target_language); } } } /** * 获取工单详情 */ public function get_ticket($ticket_id) { return $this->db->get_row($this->db->prepare( "SELECT t.*, u.user_email, u.display_name FROM {$this->db->prefix}mcs_support_tickets t LEFT JOIN {$this->db->prefix}users u ON t.user_id = u.ID WHERE t.id = %d", $ticket_id )); } /** * 获取工单回复 */ public function get_ticket_replies($ticket_id, $user_language = null) { $replies = $this->db->get_results($this->db->prepare( "SELECT r.*, u.display_name, u.user_email FROM {$this->db->prefix}mcs_ticket_replies r LEFT JOIN {$this->db->prefix}users u ON r.user_id = u.ID WHERE r.ticket_id = %d ORDER BY r.created_at ASC", $ticket_id )); // 根据用户语言提供翻译版本 if ($user_language) { foreach ($replies as &$reply) { if ($reply->original_language !== $user_language) { $translated = get_comment_meta($reply->id, '_translated_message', true); if ($translated) { $reply->translated_message = $translated; } } } } return $replies; } } ### 4.2 知识库系统 创建多语言知识库,帮助用户自助解决问题: class MCS_Knowledge_Base { private $db; public function __construct()
在当今全球化的互联网环境中,多语言支持已成为网站建设的标配功能。对于WordPress这一占据全球43%网站市场的开源平台而言,通过插件扩展其多语言功能具有巨大的实用价值和商业潜力。本教程将深入讲解如何开发一个集成了实时翻译聊天与多语言客服工具的WordPress插件,通过代码二次开发实现这一实用功能。
WordPress插件开发不仅能够满足特定业务需求,还能为开发者带来可观的收益。根据WordPress官方数据,插件目录中已有超过5.8万个免费插件,而高级插件市场更是价值数十亿美元。掌握插件开发技能,意味着您可以为全球数百万WordPress网站提供解决方案。
在开始插件开发前,我们需要搭建合适的开发环境:
- 本地开发环境:推荐使用XAMPP、MAMP或Local by Flywheel,它们提供了完整的PHP、MySQL和Apache/Nginx环境。
- 代码编辑器:Visual Studio Code、PHPStorm或Sublime Text都是优秀的选择,确保安装PHP智能提示和WordPress代码片段插件。
-
WordPress安装:下载最新版WordPress并安装在本地环境中,建议使用调试模式,在wp-config.php中添加:
define('WP_DEBUG', true); define('WP_DEBUG_LOG', true); define('WP_DEBUG_DISPLAY', false);
创建一个标准的WordPress插件需要遵循特定的目录结构和文件组织:
multilingual-chat-support/
│
├── multilingual-chat-support.php # 主插件文件
├── uninstall.php # 卸载脚本
├── readme.txt # 插件说明
├── assets/ # 静态资源
│ ├── css/
│ ├── js/
│ └── images/
├── includes/ # 包含文件
│ ├── class-chat-handler.php
│ ├── class-translation-api.php
│ └── class-admin-settings.php
├── languages/ # 国际化文件
├── templates/ # 前端模板
└── vendor/ # 第三方库(如果需要)
主插件文件是插件的入口点,需要包含标准的插件头部信息:
<?php
/**
* Plugin Name: 多语言实时聊天与客服工具
* Plugin URI: https://yourwebsite.com/multilingual-chat
* Description: 为WordPress网站添加实时翻译聊天和多语言客服功能
* Version: 1.0.0
* Author: 您的名称
* Author URI: https://yourwebsite.com
* License: GPL v2 or later
* Text Domain: multilingual-chat
* Domain Path: /languages
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('MCS_VERSION', '1.0.0');
define('MCS_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('MCS_PLUGIN_URL', plugin_dir_url(__FILE__));
define('MCS_PLUGIN_BASENAME', plugin_basename(__FILE__));
// 初始化插件
require_once MCS_PLUGIN_DIR . 'includes/class-plugin-init.php';
$mcs_plugin = new MCS_Plugin_Init();
$mcs_plugin->run();
实时翻译是插件的核心功能之一。我们可以选择多种翻译API:
- Google Cloud Translation API:准确度高,支持100多种语言
- Microsoft Azure Translator:性价比优秀,有免费额度
- DeepL API:欧洲语言翻译质量极高
- 百度翻译API:中文翻译效果优秀
以下是如何集成Google翻译API的示例:
<?php
class MCS_Translation_API {
private $api_key;
private $api_url = 'https://translation.googleapis.com/language/translate/v2';
public function __construct($api_key) {
$this->api_key = $api_key;
}
/**
* 翻译文本
* @param string $text 要翻译的文本
* @param string $target_lang 目标语言代码
* @param string $source_lang 源语言代码(可选,自动检测)
* @return array 翻译结果
*/
public function translate($text, $target_lang, $source_lang = null) {
$args = array(
'key' => $this->api_key,
'q' => $text,
'target' => $target_lang,
'format' => 'text'
);
if ($source_lang) {
$args['source'] = $source_lang;
}
$url = add_query_arg($args, $this->api_url);
$response = wp_remote_get($url, array(
'timeout' => 15,
'headers' => array(
'Content-Type' => 'application/json',
)
));
if (is_wp_error($response)) {
return array(
'success' => false,
'error' => $response->get_error_message()
);
}
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if (isset($data['error'])) {
return array(
'success' => false,
'error' => $data['error']['message']
);
}
return array(
'success' => true,
'translatedText' => $data['data']['translations'][0]['translatedText'],
'detectedSourceLanguage' => $data['data']['translations'][0]['detectedSourceLanguage']
);
}
/**
* 批量翻译
*/
public function translate_batch($texts, $target_lang, $source_lang = null) {
// 实现批量翻译逻辑
}
/**
* 获取支持的语言列表
*/
public function get_supported_languages() {
$url = 'https://translation.googleapis.com/language/translate/v2/languages';
$url = add_query_arg(array(
'key' => $this->api_key,
'target' => 'zh-CN'
), $url);
// 发送请求并处理响应
}
}
为了减少API调用次数和提高响应速度,我们需要实现翻译缓存:
class MCS_Translation_Cache {
private $cache_table;
public function __construct() {
global $wpdb;
$this->cache_table = $wpdb->prefix . 'mcs_translation_cache';
}
/**
* 创建缓存表
*/
public function create_table() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS {$this->cache_table} (
id bigint(20) NOT NULL AUTO_INCREMENT,
source_text text NOT NULL,
source_lang varchar(10) DEFAULT '',
target_lang varchar(10) NOT NULL,
translated_text text NOT NULL,
hash varchar(32) NOT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY hash (hash),
KEY source_lang (source_lang),
KEY target_lang (target_lang)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
/**
* 获取缓存翻译
*/
public function get($text, $target_lang, $source_lang = '') {
global $wpdb;
$hash = md5($text . $source_lang . $target_lang);
$result = $wpdb->get_row($wpdb->prepare(
"SELECT translated_text FROM {$this->cache_table} WHERE hash = %s",
$hash
));
return $result ? $result->translated_text : false;
}
/**
* 设置缓存
*/
public function set($text, $translated_text, $target_lang, $source_lang = '') {
global $wpdb;
$hash = md5($text . $source_lang . $target_lang);
$wpdb->insert(
$this->cache_table,
array(
'source_text' => $text,
'source_lang' => $source_lang,
'target_lang' => $target_lang,
'translated_text' => $translated_text,
'hash' => $hash
),
array('%s', '%s', '%s', '%s', '%s')
);
}
/**
* 清理旧缓存
*/
public function cleanup($days_old = 30) {
global $wpdb;
$wpdb->query($wpdb->prepare(
"DELETE FROM {$this->cache_table} WHERE created_at < DATE_SUB(NOW(), INTERVAL %d DAY)",
$days_old
));
}
}
实时聊天需要双向通信,我们可以使用WebSocket技术:
class MCS_WebSocket_Server {
private $server;
private $clients = [];
private $translator;
public function __construct($translator) {
$this->translator = $translator;
}
/**
* 启动WebSocket服务器
*/
public function start($host = '0.0.0.0', $port = 8080) {
$this->server = new SwooleWebSocketServer($host, $port);
$this->server->on('open', function($server, $request) {
$this->clients[$request->fd] = [
'fd' => $request->fd,
'user_id' => 0,
'language' => 'en',
'room_id' => null
];
echo "客户端 {$request->fd} 已连接n";
});
$this->server->on('message', function($server, $frame) {
$this->handle_message($frame->fd, $frame->data);
});
$this->server->on('close', function($server, $fd) {
unset($this->clients[$fd]);
echo "客户端 {$fd} 已断开连接n";
});
$this->server->start();
}
/**
* 处理客户端消息
*/
private function handle_message($fd, $data) {
$message = json_decode($data, true);
if (!$message || !isset($message['type'])) {
return;
}
switch ($message['type']) {
case 'auth':
$this->handle_auth($fd, $message);
break;
case 'chat_message':
$this->handle_chat_message($fd, $message);
break;
case 'join_room':
$this->handle_join_room($fd, $message);
break;
case 'typing':
$this->handle_typing($fd, $message);
break;
}
}
/**
* 处理认证
*/
private function handle_auth($fd, $message) {
if (isset($message['user_id'], $message['language'])) {
$this->clients[$fd]['user_id'] = intval($message['user_id']);
$this->clients[$fd]['language'] = sanitize_text_field($message['language']);
$this->send_to_client($fd, [
'type' => 'auth_success',
'message' => '认证成功'
]);
}
}
/**
* 处理聊天消息
*/
private function handle_chat_message($fd, $message) {
if (!isset($message['content'], $message['room_id'])) {
return;
}
$client = $this->clients[$fd];
$room_id = $message['room_id'];
$original_content = sanitize_text_field($message['content']);
// 保存消息到数据库
$message_id = $this->save_message_to_db(
$client['user_id'],
$room_id,
$original_content,
$client['language']
);
// 向房间内所有客户端发送消息(自动翻译)
$this->broadcast_to_room($room_id, [
'type' => 'new_message',
'message_id' => $message_id,
'sender_id' => $client['user_id'],
'original_content' => $original_content,
'original_language' => $client['language'],
'timestamp' => current_time('mysql')
], $fd);
}
/**
* 向客户端发送消息
*/
private function send_to_client($fd, $data) {
if ($this->server->exist($fd)) {
$this->server->push($fd, json_encode($data));
}
}
/**
* 向房间广播消息
*/
private function broadcast_to_room($room_id, $data, $exclude_fd = null) {
foreach ($this->clients as $client) {
if ($client['room_id'] == $room_id && $client['fd'] != $exclude_fd) {
// 根据客户端语言翻译消息
if (isset($data['original_content'])) {
$translation = $this->translator->translate(
$data['original_content'],
$client['language'],
$data['original_language']
);
if ($translation['success']) {
$data['translated_content'] = $translation['translatedText'];
}
}
$this->send_to_client($client['fd'], $data);
}
}
}
}
创建响应式的前端聊天界面:
class MCSChatWidget {
constructor(options) {
this.options = Object.assign({
position: 'bottom-right',
primaryColor: '#0073aa',
defaultLanguage: 'en',
availableLanguages: ['en', 'zh-CN', 'es', 'fr', 'de', 'ja'],
autoOpen: false,
greetingMessage: '您好!需要什么帮助吗?'
}, options);
this.ws = null;
this.isConnected = false;
this.currentRoom = null;
this.userLanguage = this.detectUserLanguage();
this.init();
}
/**
* 初始化聊天组件
*/
init() {
this.createWidgetHTML();
this.bindEvents();
this.loadUserSettings();
if (this.options.autoOpen) {
setTimeout(() => this.openChat(), 1000);
}
}
/**
* 创建聊天界面HTML
*/
createWidgetHTML() {
// 创建主容器
this.container = document.createElement('div');
this.container.className = 'mcs-chat-container';
this.container.style.cssText = `
position: fixed;
z-index: 999999;
${this.getPositionStyles()}
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
`;
// 创建聊天按钮
this.chatButton = document.createElement('div');
this.chatButton.className = 'mcs-chat-button';
this.chatButton.innerHTML = `
<svg width="24" height="24" viewBox="0 0 24 24" fill="white">
<path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-2 12H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z"/>
</svg>
`;
// 创建聊天窗口
this.chatWindow = document.createElement('div');
this.chatWindow.className = 'mcs-chat-window';
this.chatWindow.style.display = 'none';
this.chatWindow.innerHTML = `
<div class="mcs-chat-header">
<h3>${this.options.greetingMessage}</h3>
<div class="mcs-header-actions">
<select class="mcs-language-selector">
${this.options.availableLanguages.map(lang =>
`<option value="${lang}" ${lang === this.userLanguage ? 'selected' : ''}>
${this.getLanguageName(lang)}
</option>`
).join('')}
</select>
<button class="mcs-close-chat">×</button>
</div>
</div>
<div class="mcs-chat-messages"></div>
<div class="mcs-chat-input-area">
<textarea class="mcs-message-input" placeholder="输入消息..."></textarea>
<button class="mcs-send-button">发送</button>
</div>
`;
this.container.appendChild(this.chatButton);
this.container.appendChild(this.chatWindow);
document.body.appendChild(this.container);
this.addStyles();
}
/**
* 连接WebSocket服务器
*/
connectWebSocket() {
if (this.ws && this.isConnected) return;
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = `${protocol}//${window.location.hostname}:8080`;
this.ws = new WebSocket(wsUrl);
this.ws.onopen = () => {
this.isConnected = true;
this.authenticate();
this.showNotification('已连接到聊天服务器');
};
this.ws.onmessage = (event) => {
this.handleWebSocketMessage(JSON.parse(event.data));
this.ws.onclose = () => {
this.isConnected = false;
this.showNotification('连接已断开,正在尝试重新连接...');
setTimeout(() => this.connectWebSocket(), 3000);
};
this.ws.onerror = (error) => {
console.error('WebSocket错误:', error);
};
}
/**
* 处理WebSocket消息
*/
handleWebSocketMessage(data) {
switch (data.type) {
case 'auth_success':
this.handleAuthSuccess(data);
break;
case 'new_message':
this.handleNewMessage(data);
break;
case 'typing_indicator':
this.handleTypingIndicator(data);
break;
case 'room_joined':
this.handleRoomJoined(data);
break;
case 'error':
this.showNotification(data.message, 'error');
break;
}
}
/**
* 处理新消息
*/
handleNewMessage(data) {
const messagesContainer = this.chatWindow.querySelector('.mcs-chat-messages');
const messageElement = this.createMessageElement(data);
messagesContainer.appendChild(messageElement);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
// 显示桌面通知(如果用户不在当前标签页)
if (document.hidden && this.options.desktopNotifications) {
this.showDesktopNotification(data);
}
}
/**
* 创建消息元素
*/
createMessageElement(data) {
const messageDiv = document.createElement('div');
messageDiv.className = `mcs-message ${data.sender_id === this.userId ? 'own-message' : 'other-message'}`;
const time = new Date(data.timestamp).toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit'
});
let content = `
<div class="mcs-message-content">
<div class="mcs-original-text">${this.escapeHtml(data.original_content)}</div>
`;
if (data.translated_content && data.translated_content !== data.original_content) {
content += `
<div class="mcs-translated-text">
<small>翻译:</small> ${this.escapeHtml(data.translated_content)}
</div>
`;
}
content += `
<div class="mcs-message-time">${time}</div>
</div>
`;
messageDiv.innerHTML = content;
return messageDiv;
}
/**
* 绑定事件
*/
bindEvents() {
// 聊天按钮点击事件
this.chatButton.addEventListener('click', () => this.toggleChat());
// 关闭按钮事件
this.chatWindow.querySelector('.mcs-close-chat').addEventListener('click', () => this.closeChat());
// 发送按钮事件
this.chatWindow.querySelector('.mcs-send-button').addEventListener('click', () => this.sendMessage());
// 输入框回车发送
this.chatWindow.querySelector('.mcs-message-input').addEventListener('keypress', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
this.sendMessage();
}
});
// 输入框输入事件(显示正在输入)
this.chatWindow.querySelector('.mcs-message-input').addEventListener('input', (e) => {
this.sendTypingIndicator();
});
// 语言选择器变更事件
this.chatWindow.querySelector('.mcs-language-selector').addEventListener('change', (e) => {
this.userLanguage = e.target.value;
this.saveUserSettings();
this.updateLanguage();
});
}
/**
* 发送消息
*/
sendMessage() {
const input = this.chatWindow.querySelector('.mcs-message-input');
const message = input.value.trim();
if (!message || !this.isConnected || !this.currentRoom) return;
// 发送到WebSocket服务器
this.ws.send(JSON.stringify({
type: 'chat_message',
room_id: this.currentRoom,
content: message,
language: this.userLanguage
}));
// 清空输入框
input.value = '';
input.focus();
}
/**
* 发送正在输入指示
*/
sendTypingIndicator() {
if (!this.isConnected || !this.currentRoom) return;
this.ws.send(JSON.stringify({
type: 'typing',
room_id: this.currentRoom,
is_typing: true
}));
// 清除之前的定时器
if (this.typingTimeout) {
clearTimeout(this.typingTimeout);
}
// 设置停止输入指示
this.typingTimeout = setTimeout(() => {
if (this.isConnected) {
this.ws.send(JSON.stringify({
type: 'typing',
room_id: this.currentRoom,
is_typing: false
}));
}
}, 1000);
}
/**
* 添加CSS样式
*/
addStyles() {
const style = document.createElement('style');
style.textContent = `
.mcs-chat-button {
width: 60px;
height: 60px;
background-color: ${this.options.primaryColor};
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
transition: all 0.3s ease;
}
.mcs-chat-button:hover {
transform: scale(1.1);
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
}
.mcs-chat-window {
width: 350px;
height: 500px;
background: white;
border-radius: 10px;
box-shadow: 0 5px 25px rgba(0,0,0,0.15);
display: flex;
flex-direction: column;
overflow: hidden;
}
.mcs-chat-header {
background: ${this.options.primaryColor};
color: white;
padding: 15px;
display: flex;
justify-content: space-between;
align-items: center;
}
.mcs-chat-header h3 {
margin: 0;
font-size: 16px;
font-weight: 500;
}
.mcs-header-actions {
display: flex;
align-items: center;
gap: 10px;
}
.mcs-language-selector {
background: rgba(255,255,255,0.2);
border: none;
color: white;
padding: 5px;
border-radius: 4px;
font-size: 12px;
}
.mcs-close-chat {
background: none;
border: none;
color: white;
font-size: 24px;
cursor: pointer;
line-height: 1;
}
.mcs-chat-messages {
flex: 1;
padding: 15px;
overflow-y: auto;
background: #f8f9fa;
}
.mcs-message {
margin-bottom: 15px;
max-width: 80%;
}
.mcs-message.own-message {
margin-left: auto;
}
.mcs-message.other-message {
margin-right: auto;
}
.mcs-message-content {
background: white;
padding: 10px 15px;
border-radius: 18px;
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
}
.own-message .mcs-message-content {
background: ${this.options.primaryColor};
color: white;
border-bottom-right-radius: 4px;
}
.other-message .mcs-message-content {
border-bottom-left-radius: 4px;
}
.mcs-translated-text {
margin-top: 5px;
padding-top: 5px;
border-top: 1px dashed rgba(0,0,0,0.1);
font-size: 0.9em;
color: #666;
}
.own-message .mcs-translated-text {
border-top-color: rgba(255,255,255,0.3);
color: rgba(255,255,255,0.9);
}
.mcs-message-time {
font-size: 11px;
color: #999;
margin-top: 5px;
text-align: right;
}
.mcs-chat-input-area {
border-top: 1px solid #e0e0e0;
padding: 15px;
background: white;
}
.mcs-message-input {
width: 100%;
border: 1px solid #ddd;
border-radius: 20px;
padding: 10px 15px;
resize: none;
font-family: inherit;
font-size: 14px;
min-height: 40px;
max-height: 100px;
box-sizing: border-box;
}
.mcs-message-input:focus {
outline: none;
border-color: ${this.options.primaryColor};
}
.mcs-send-button {
background: ${this.options.primaryColor};
color: white;
border: none;
border-radius: 20px;
padding: 8px 20px;
margin-top: 10px;
cursor: pointer;
font-weight: 500;
float: right;
}
.mcs-send-button:hover {
opacity: 0.9;
}
@media (max-width: 480px) {
.mcs-chat-window {
width: 100%;
height: 100%;
border-radius: 0;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
}
`;
document.head.appendChild(style);
}
}
## 第四章:多语言客服工具集成
### 4.1 客服工单系统
除了实时聊天,我们还需要一个完整的客服工单系统:
class MCS_Support_Ticket_System {
private $db;
public function __construct() {
global $wpdb;
$this->db = $wpdb;
}
/**
* 创建工单表
*/
public function create_tables() {
$charset_collate = $this->db->get_charset_collate();
$tickets_table = $this->db->prefix . 'mcs_support_tickets';
$tickets_sql = "CREATE TABLE IF NOT EXISTS $tickets_table (
id bigint(20) NOT NULL AUTO_INCREMENT,
ticket_number varchar(50) NOT NULL,
user_id bigint(20) NOT NULL,
subject varchar(255) NOT NULL,
description text NOT NULL,
status varchar(50) DEFAULT 'open',
priority varchar(50) DEFAULT 'medium',
language varchar(10) NOT NULL,
assigned_to bigint(20) DEFAULT 0,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY ticket_number (ticket_number),
KEY user_id (user_id),
KEY status (status),
KEY assigned_to (assigned_to)
) $charset_collate;";
$replies_table = $this->db->prefix . 'mcs_ticket_replies';
$replies_sql = "CREATE TABLE IF NOT EXISTS $replies_table (
id bigint(20) NOT NULL AUTO_INCREMENT,
ticket_id bigint(20) NOT NULL,
user_id bigint(20) NOT NULL,
message text NOT NULL,
original_language varchar(10) NOT NULL,
is_internal tinyint(1) DEFAULT 0,
attachments text,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY ticket_id (ticket_id),
KEY user_id (user_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($tickets_sql);
dbDelta($replies_sql);
}
/**
* 创建新工单
*/
public function create_ticket($data) {
$ticket_number = 'TICKET-' . date('Ymd') . '-' . strtoupper(wp_generate_password(6, false));
$result = $this->db->insert(
$this->db->prefix . 'mcs_support_tickets',
array(
'ticket_number' => $ticket_number,
'user_id' => $data['user_id'],
'subject' => sanitize_text_field($data['subject']),
'description' => wp_kses_post($data['description']),
'language' => sanitize_text_field($data['language']),
'priority' => $data['priority'] ?? 'medium',
'status' => 'open'
),
array('%s', '%d', '%s', '%s', '%s', '%s', '%s')
);
if ($result) {
$ticket_id = $this->db->insert_id;
// 发送通知邮件
$this->send_ticket_notification($ticket_id, 'created');
// 记录活动日志
$this->log_ticket_activity($ticket_id, 'ticket_created', $data['user_id']);
return array(
'success' => true,
'ticket_id' => $ticket_id,
'ticket_number' => $ticket_number
);
}
return array(
'success' => false,
'error' => '创建工单失败'
);
}
/**
* 添加工单回复
*/
public function add_reply($ticket_id, $data) {
$ticket = $this->get_ticket($ticket_id);
if (!$ticket) {
return array('success' => false, 'error' => '工单不存在');
}
$result = $this->db->insert(
$this->db->prefix . 'mcs_ticket_replies',
array(
'ticket_id' => $ticket_id,
'user_id' => $data['user_id'],
'message' => wp_kses_post($data['message']),
'original_language' => $data['language'],
'is_internal' => $data['is_internal'] ?? 0
),
array('%d', '%d', '%s', '%s', '%d')
);
if ($result) {
// 更新工单状态
$this->update_ticket_status($ticket_id, $data['user_id']);
// 发送通知
$this->send_ticket_notification($ticket_id, 'replied', $data['user_id']);
// 自动翻译回复内容
$this->translate_ticket_reply($this->db->insert_id, $ticket['language']);
return array('success' => true, 'reply_id' => $this->db->insert_id);
}
return array('success' => false, 'error' => '添加回复失败');
}
/**
* 自动翻译工单回复
*/
private function translate_ticket_reply($reply_id, $target_language) {
$reply = $this->db->get_row($this->db->prepare(
"SELECT * FROM {$this->db->prefix}mcs_ticket_replies WHERE id = %d",
$reply_id
));
if ($reply && $reply->original_language !== $target_language) {
$translation = $this->translate_content($reply->message, $target_language, $reply->original_language);
if ($translation['success']) {
// 保存翻译后的内容
update_comment_meta($reply_id, '_translated_message', $translation['translatedText']);
update_comment_meta($reply_id, '_translation_language', $target_language);
}
}
}
/**
* 获取工单详情
*/
public function get_ticket($ticket_id) {
return $this->db->get_row($this->db->prepare(
"SELECT t.*, u.user_email, u.display_name
FROM {$this->db->prefix}mcs_support_tickets t
LEFT JOIN {$this->db->prefix}users u ON t.user_id = u.ID
WHERE t.id = %d",
$ticket_id
));
}
/**
* 获取工单回复
*/
public function get_ticket_replies($ticket_id, $user_language = null) {
$replies = $this->db->get_results($this->db->prepare(
"SELECT r.*, u.display_name, u.user_email
FROM {$this->db->prefix}mcs_ticket_replies r
LEFT JOIN {$this->db->prefix}users u ON r.user_id = u.ID
WHERE r.ticket_id = %d
ORDER BY r.created_at ASC",
$ticket_id
));
// 根据用户语言提供翻译版本
if ($user_language) {
foreach ($replies as &$reply) {
if ($reply->original_language !== $user_language) {
$translated = get_comment_meta($reply->id, '_translated_message', true);
if ($translated) {
$reply->translated_message = $translated;
}
}
}
}
return $replies;
}
}
### 4.2 知识库系统
创建多语言知识库,帮助用户自助解决问题:
class MCS_Knowledge_Base {
private $db;
public function __construct()


