首页 / 应用软件 / 详细教程,集成网站实时在线聊天与通讯应用

详细教程,集成网站实时在线聊天与通讯应用

详细教程:集成网站实时在线聊天与通讯应用,通过WordPress代码二次开发实现常用互联网小工具功能

引言:为什么网站需要实时通讯功能?

在当今数字化时代,网站已经不再是单向信息传递的平台。用户期望与网站所有者进行即时互动,获取实时帮助或咨询。研究表明,集成实时聊天功能的网站可以将转化率提高20-40%,客户满意度提升30%以上。对于电商网站、服务型企业或内容平台而言,实时通讯功能已成为提升用户体验和业务效率的关键工具。

WordPress作为全球最流行的内容管理系统,占据了互联网上超过40%的网站份额。其强大的可扩展性使得开发者能够通过代码二次开发,集成各种实用功能。本教程将详细指导您如何通过WordPress代码二次开发,实现网站实时在线聊天与通讯应用,并扩展其他常用互联网小工具功能。

第一部分:准备工作与环境配置

1.1 开发环境要求

在开始之前,请确保您的开发环境满足以下要求:

  • WordPress 5.0或更高版本
  • PHP 7.4或更高版本(推荐PHP 8.0+)
  • MySQL 5.6或更高版本
  • 支持HTTPS的网站(实时通讯通常需要安全连接)
  • 基本的HTML、CSS、JavaScript和PHP知识
  • 代码编辑器(如VS Code、Sublime Text等)

1.2 创建开发子主题

为了避免直接修改主题文件导致更新时丢失更改,我们首先创建一个子主题:

  1. 在WordPress的wp-content/themes/目录下创建新文件夹,命名为my-custom-theme
  2. 在该文件夹中创建style.css文件,添加以下内容:
/*
Theme Name: My Custom Theme
Template: twentytwentythree  // 根据您使用的父主题修改
Version: 1.0.0
Description: 自定义主题,用于集成实时聊天功能
*/

/* 导入父主题样式 */
@import url("../twentytwentythree/style.css");
  1. 创建functions.php文件,用于添加自定义功能:
<?php
// 子主题 functions.php
add_action('wp_enqueue_scripts', 'my_custom_theme_enqueue_styles');
function my_custom_theme_enqueue_styles() {
    // 加载父主题样式
    wp_enqueue_style('parent-style', get_template_directory_uri() . '/style.css');
    
    // 加载子主题样式
    wp_enqueue_style('child-style', get_stylesheet_directory_uri() . '/style.css', array('parent-style'));
}

1.3 安装必要插件

我们将使用一些插件作为基础,然后通过代码扩展功能:

  1. Advanced Custom Fields (ACF) - 用于创建自定义设置页面
  2. Query Monitor - 开发调试工具(可选但推荐)

第二部分:构建实时聊天系统

2.1 实时通讯技术选型

实现实时通讯有多种技术方案:

  1. WebSocket:全双工通信,实时性最好
  2. Server-Sent Events (SSE):服务器向客户端推送消息
  3. 长轮询:兼容性好但效率较低
  4. 第三方服务集成:如Socket.io、Pusher等

本教程将采用WebSocket技术,因为它提供最低的延迟和最高的效率。

2.2 创建聊天数据库结构

在WordPress数据库中创建自定义表来存储聊天消息:

// 在functions.php中添加
function create_chat_tables() {
    global $wpdb;
    $charset_collate = $wpdb->get_charset_collate();
    $table_name = $wpdb->prefix . 'chat_messages';
    
    $sql = "CREATE TABLE IF NOT EXISTS $table_name (
        id mediumint(9) NOT NULL AUTO_INCREMENT,
        sender_id mediumint(9) NOT NULL,
        receiver_id mediumint(9) NOT NULL,
        message text NOT NULL,
        timestamp datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
        is_read tinyint(1) DEFAULT 0 NOT NULL,
        PRIMARY KEY (id)
    ) $charset_collate;";
    
    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($sql);
}
add_action('after_setup_theme', 'create_chat_tables');

2.3 实现WebSocket服务器

由于PHP对WebSocket的原生支持有限,我们将使用Ratchet库来创建WebSocket服务器:

  1. 通过Composer安装Ratchet:

    composer require cboden/ratchet
  2. 创建WebSocket服务器文件websocket-server.php
<?php
require dirname(__DIR__) . '/vendor/autoload.php';

use RatchetMessageComponentInterface;
use RatchetConnectionInterface;
use RatchetServerIoServer;
use RatchetHttpHttpServer;
use RatchetWebSocketWsServer;

class Chat implements MessageComponentInterface {
    protected $clients;
    protected $users;

    public function __construct() {
        $this->clients = new SplObjectStorage;
        $this->users = [];
    }

    public function onOpen(ConnectionInterface $conn) {
        $this->clients->attach($conn);
        echo "新连接: {$conn->resourceId}n";
    }

    public function onMessage(ConnectionInterface $from, $msg) {
        $data = json_decode($msg, true);
        
        if ($data['type'] === 'register') {
            // 用户注册
            $this->users[$data['userId']] = $from;
            echo "用户 {$data['userId']} 已注册n";
        } elseif ($data['type'] === 'message') {
            // 发送消息
            $messageData = [
                'type' => 'message',
                'from' => $data['from'],
                'to' => $data['to'],
                'message' => $data['message'],
                'timestamp' => date('Y-m-d H:i:s')
            ];
            
            // 存储到数据库
            $this->saveMessageToDB($data);
            
            // 发送给接收者(如果在线)
            if (isset($this->users[$data['to']])) {
                $this->users[$data['to']]->send(json_encode($messageData));
            }
            
            // 回发给发送者确认
            $from->send(json_encode(['type' => 'sent', 'messageId' => uniqid()]));
        }
    }

    public function onClose(ConnectionInterface $conn) {
        $this->clients->detach($conn);
        
        // 从用户列表中移除
        $userId = array_search($conn, $this->users, true);
        if ($userId !== false) {
            unset($this->users[$userId]);
        }
        
        echo "连接关闭: {$conn->resourceId}n";
    }

    public function onError(ConnectionInterface $conn, Exception $e) {
        echo "错误: {$e->getMessage()}n";
        $conn->close();
    }
    
    private function saveMessageToDB($data) {
        // 这里简化处理,实际应用中需要连接到数据库
        // 并存储消息
        file_put_contents('chat_log.txt', 
            date('Y-m-d H:i:s') . " - {$data['from']} 给 {$data['to']}: {$data['message']}n", 
            FILE_APPEND
        );
    }
}

// 运行服务器
$server = IoServer::factory(
    new HttpServer(
        new WsServer(
            new Chat()
        )
    ),
    8080  // 端口号
);

echo "WebSocket服务器运行在端口 8080n";
$server->run();

2.4 前端聊天界面实现

创建聊天界面组件:

<!-- 在主题中创建 chat-widget.php -->
<div id="chat-container" class="chat-container">
    <div class="chat-header">
        <h3>在线客服</h3>
        <button id="chat-toggle" class="chat-toggle">×</button>
    </div>
    
    <div class="chat-body">
        <div id="chat-messages" class="chat-messages">
            <!-- 消息将在这里显示 -->
        </div>
        
        <div class="chat-input-area">
            <textarea id="chat-input" placeholder="输入消息..." rows="3"></textarea>
            <button id="chat-send" class="chat-send-btn">发送</button>
        </div>
    </div>
</div>

<button id="chat-launcher" class="chat-launcher">
    <span class="chat-icon">💬</span>
</button>

添加CSS样式:

/* 在style.css中添加 */
.chat-launcher {
    position: fixed;
    bottom: 20px;
    right: 20px;
    width: 60px;
    height: 60px;
    border-radius: 50%;
    background: #0073aa;
    color: white;
    border: none;
    cursor: pointer;
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
    z-index: 9999;
    font-size: 24px;
}

.chat-container {
    position: fixed;
    bottom: 90px;
    right: 20px;
    width: 350px;
    height: 500px;
    background: white;
    border-radius: 10px;
    box-shadow: 0 5px 20px rgba(0,0,0,0.2);
    display: none;
    flex-direction: column;
    z-index: 9998;
    overflow: hidden;
}

.chat-container.active {
    display: flex;
}

.chat-header {
    background: #0073aa;
    color: white;
    padding: 15px;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.chat-toggle {
    background: none;
    border: none;
    color: white;
    font-size: 24px;
    cursor: pointer;
}

.chat-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.chat-messages {
    flex: 1;
    padding: 15px;
    overflow-y: auto;
    background: #f9f9f9;
}

.message {
    margin-bottom: 10px;
    padding: 8px 12px;
    border-radius: 18px;
    max-width: 80%;
    word-wrap: break-word;
}

.message.sent {
    background: #0073aa;
    color: white;
    margin-left: auto;
}

.message.received {
    background: #e9e9e9;
    color: #333;
    margin-right: auto;
}

.chat-input-area {
    border-top: 1px solid #ddd;
    padding: 15px;
}

#chat-input {
    width: 100%;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
    resize: none;
    font-family: inherit;
}

.chat-send-btn {
    width: 100%;
    margin-top: 10px;
    padding: 10px;
    background: #0073aa;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
}

2.5 JavaScript实现实时通讯

创建前端JavaScript文件处理WebSocket连接:

// 创建 /js/chat-client.js
class ChatClient {
    constructor() {
        this.socket = null;
        this.userId = null;
        this.isConnected = false;
        this.reconnectAttempts = 0;
        this.maxReconnectAttempts = 5;
        
        this.init();
    }
    
    init() {
        // 获取当前用户ID(如果是登录用户)
        this.userId = window.chatConfig?.userId || 'guest_' + Math.random().toString(36).substr(2, 9);
        
        // 初始化UI事件
        this.initUIEvents();
        
        // 连接WebSocket服务器
        this.connect();
    }
    
    connect() {
        const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
        const wsUrl = `${protocol}//${window.location.hostname}:8080`;
        
        this.socket = new WebSocket(wsUrl);
        
        this.socket.onopen = () => {
            console.log('WebSocket连接已建立');
            this.isConnected = true;
            this.reconnectAttempts = 0;
            
            // 注册用户
            this.registerUser();
        };
        
        this.socket.onmessage = (event) => {
            this.handleMessage(JSON.parse(event.data));
        };
        
        this.socket.onclose = () => {
            console.log('WebSocket连接已关闭');
            this.isConnected = false;
            this.handleReconnection();
        };
        
        this.socket.onerror = (error) => {
            console.error('WebSocket错误:', error);
        };
    }
    
    registerUser() {
        if (this.socket && this.socket.readyState === WebSocket.OPEN) {
            this.socket.send(JSON.stringify({
                type: 'register',
                userId: this.userId
            }));
        }
    }
    
    handleMessage(data) {
        switch(data.type) {
            case 'message':
                this.displayMessage(data);
                break;
            case 'sent':
                console.log('消息发送成功:', data.messageId);
                break;
            default:
                console.log('收到未知消息类型:', data);
        }
    }
    
    sendMessage(toUserId, message) {
        if (!this.isConnected || !this.socket) {
            alert('连接已断开,请刷新页面重试');
            return;
        }
        
        if (!message.trim()) {
            return;
        }
        
        const messageData = {
            type: 'message',
            from: this.userId,
            to: toUserId,
            message: message.trim()
        };
        
        this.socket.send(JSON.stringify(messageData));
        
        // 在本地显示已发送的消息
        this.displayMessage({
            ...messageData,
            timestamp: new Date().toISOString()
        }, true);
        
        // 清空输入框
        document.getElementById('chat-input').value = '';
    }
    
    displayMessage(data, isSent = false) {
        const messagesContainer = document.getElementById('chat-messages');
        const messageElement = document.createElement('div');
        
        messageElement.className = `message ${isSent ? 'sent' : 'received'}`;
        messageElement.innerHTML = `
            <div class="message-content">${this.escapeHtml(data.message)}</div>
            <div class="message-time">${new Date(data.timestamp).toLocaleTimeString()}</div>
        `;
        
        messagesContainer.appendChild(messageElement);
        messagesContainer.scrollTop = messagesContainer.scrollHeight;
    }
    
    initUIEvents() {
        // 切换聊天窗口显示/隐藏
        document.getElementById('chat-toggle').addEventListener('click', () => {
            document.getElementById('chat-container').classList.remove('active');
        });
        
        document.getElementById('chat-launcher').addEventListener('click', () => {
            document.getElementById('chat-container').classList.toggle('active');
        });
        
        // 发送消息
        document.getElementById('chat-send').addEventListener('click', () => {
            const input = document.getElementById('chat-input');
            const message = input.value;
            
            // 这里假设客服ID为'admin',实际应用中应该动态获取
            this.sendMessage('admin', message);
        });
        
        // 按Enter发送消息,Ctrl+Enter换行
        document.getElementById('chat-input').addEventListener('keydown', (e) => {
            if (e.key === 'Enter' && !e.ctrlKey && !e.shiftKey) {
                e.preventDefault();
                document.getElementById('chat-send').click();
            }
        });
    }
    
    handleReconnection() {
        if (this.reconnectAttempts < this.maxReconnectAttempts) {
            this.reconnectAttempts++;
            const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
            
            console.log(`尝试重新连接 (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`);
            
            setTimeout(() => {
                this.connect();
            }, delay);
        } else {
            console.error('达到最大重连次数,连接失败');
        }
    }
    
    escapeHtml(text) {
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }
}

// 页面加载完成后初始化聊天客户端
document.addEventListener('DOMContentLoaded', () => {
    window.chatClient = new ChatClient();
});

2.6 集成到WordPress

将聊天系统集成到WordPress主题中:

// 在functions.php中添加
function enqueue_chat_scripts() {
    // 只在前端页面加载聊天脚本
    if (!is_admin()) {
        // 传递当前用户信息到JavaScript
        $current_user = wp_get_current_user();
        $user_data = [
            'userId' => $current_user->ID ? 'user_' . $current_user->ID : 'guest_' . uniqid(),
            'userName' => $current_user->ID ? $current_user->display_name : '访客',
            'isAdmin' => current_user_can('administrator')
        ];
        
        wp_enqueue_script('chat-client', get_stylesheet_directory_uri() . '/js/chat-client.js', [], '1.0.0', true);
        wp_localize_script('chat-client', 'chatConfig', $user_data);
        
        // 加载聊天样式
        wp_enqueue_style('chat-style', get_stylesheet_directory_uri() . '/css/chat-style.css');
    }
}
add_action('wp_enqueue_scripts', 'enqueue_chat_scripts');

// 在页脚添加聊天HTML
function add_chat_widget() {
    if (!is_admin()) {
        include get_stylesheet_directory() . '/chat-widget.php';
    }
}
add_action('wp_footer', 'add_chat_widget');

第三部分:扩展其他互联网小工具功能

3.1 创建工具管理面板

使用Advanced Custom Fields创建工具管理面板:

// 在functions.php中添加ACF选项页面
if (function_exists('acf_add_options_page')) {
    acf_add_options_page([
        'page_title' => '网站工具设置',
        'menu_title' => '网站工具',

网站工具设置',

    'capability' => 'manage_options',
    'redirect' => false
]);

}


### 3.2 实现访客计数器

创建一个简单的访客计数器小工具:

// 在functions.php中添加
class Visitor_Counter_Widget extends WP_Widget {

public function __construct() {
    parent::__construct(
        'visitor_counter_widget',
        '访客计数器',
        ['description' => '显示网站访客统计']
    );
}

public function widget($args, $instance) {
    $title = apply_filters('widget_title', $instance['title']);
    $show_today = isset($instance['show_today']) ? $instance['show_today'] : false;
    
    echo $args['before_widget'];
    
    if (!empty($title)) {
        echo $args['before_title'] . $title . $args['after_title'];
    }
    
    $stats = $this->get_visitor_stats();
    
    echo '<div class="visitor-counter">';
    echo '<div class="counter-item total">';
    echo '<span class="counter-label">总访客</span>';
    echo '<span class="counter-value">' . number_format($stats['total']) . '</span>';
    echo '</div>';
    
    if ($show_today) {
        echo '<div class="counter-item today">';
        echo '<span class="counter-label">今日访客</span>';
        echo '<span class="counter-value">' . number_format($stats['today']) . '</span>';
        echo '</div>';
    }
    
    echo '<div class="counter-item online">';
    echo '<span class="counter-label">当前在线</span>';
    echo '<span class="counter-value">' . number_format($stats['online']) . '</span>';
    echo '</div>';
    echo '</div>';
    
    echo $args['after_widget'];
}

public function form($instance) {
    $title = isset($instance['title']) ? $instance['title'] : '网站统计';
    $show_today = isset($instance['show_today']) ? (bool) $instance['show_today'] : false;
    ?>
    <p>
        <label for="<?php echo $this->get_field_id('title'); ?>">标题:</label>
        <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" 
               name="<?php echo $this->get_field_name('title'); ?>" type="text" 
               value="<?php echo esc_attr($title); ?>">
    </p>
    <p>
        <input class="checkbox" type="checkbox" 
               id="<?php echo $this->get_field_id('show_today'); ?>"
               name="<?php echo $this->get_field_name('show_today'); ?>"
               <?php checked($show_today); ?>>
        <label for="<?php echo $this->get_field_id('show_today'); ?>">显示今日访客</label>
    </p>
    <?php
}

public function update($new_instance, $old_instance) {
    $instance = [];
    $instance['title'] = (!empty($new_instance['title'])) ? strip_tags($new_instance['title']) : '';
    $instance['show_today'] = isset($new_instance['show_today']) ? (bool) $new_instance['show_today'] : false;
    return $instance;
}

private function get_visitor_stats() {
    global $wpdb;
    
    // 获取总访客数
    $total = get_option('visitor_counter_total', 0);
    
    // 获取今日访客数
    $today = get_option('visitor_counter_today', 0);
    $today_date = get_option('visitor_counter_today_date', date('Y-m-d'));
    
    // 如果日期变化,重置今日计数
    if ($today_date != date('Y-m-d')) {
        $today = 0;
        update_option('visitor_counter_today_date', date('Y-m-d'));
        update_option('visitor_counter_today', $today);
    }
    
    // 获取在线用户数(最近5分钟内有活动的用户)
    $online_timeout = 5 * 60; // 5分钟
    $online_users = get_option('visitor_online_users', []);
    $current_time = time();
    
    // 清理过期的在线用户
    foreach ($online_users as $session_id => $last_activity) {
        if ($current_time - $last_activity > $online_timeout) {
            unset($online_users[$session_id]);
        }
    }
    
    $online = count($online_users);
    
    return [
        'total' => $total,
        'today' => $today,
        'online' => $online
    ];
}

}

// 注册小工具
function register_visitor_counter_widget() {

register_widget('Visitor_Counter_Widget');

}
add_action('widgets_init', 'register_visitor_counter_widget');

// 跟踪访客访问
function track_visitor() {

if (is_admin() || wp_doing_ajax() || wp_doing_cron()) {
    return;
}

// 使用会话ID跟踪用户
$session_id = session_id();
if (empty($session_id)) {
    session_start();
    $session_id = session_id();
}

// 更新总访客数
$total = get_option('visitor_counter_total', 0);
$today = get_option('visitor_counter_today', 0);
$today_date = get_option('visitor_counter_today_date', date('Y-m-d'));

// 检查是否是新会话
$visited_sessions = get_option('visitor_sessions', []);

if (!in_array($session_id, $visited_sessions)) {
    // 新访客
    $total++;
    $today++;
    
    $visited_sessions[] = $session_id;
    
    update_option('visitor_counter_total', $total);
    update_option('visitor_counter_today', $today);
    update_option('visitor_sessions', $visited_sessions);
    
    // 更新今日日期
    if ($today_date != date('Y-m-d')) {
        update_option('visitor_counter_today_date', date('Y-m-d'));
        update_option('visitor_counter_today', 1);
    }
}

// 更新在线用户
$online_users = get_option('visitor_online_users', []);
$online_users[$session_id] = time();
update_option('visitor_online_users', $online_users);

}
add_action('init', 'track_visitor');


### 3.3 创建天气小工具

实现一个显示当地天气的小工具:

// 在functions.php中添加
class Weather_Widget extends WP_Widget {

private $api_key = ''; // 需要从天气API服务获取

public function __construct() {
    parent::__construct(
        'weather_widget',
        '天气小工具',
        ['description' => '显示当地天气信息']
    );
    
    // 从设置获取API密钥
    $this->api_key = get_option('weather_api_key', '');
}

public function widget($args, $instance) {
    $title = apply_filters('widget_title', $instance['title']);
    $location = isset($instance['location']) ? $instance['location'] : '北京';
    $units = isset($instance['units']) ? $instance['units'] : 'metric';
    
    echo $args['before_widget'];
    
    if (!empty($title)) {
        echo $args['before_title'] . $title . $args['after_title'];
    }
    
    $weather_data = $this->get_weather_data($location, $units);
    
    if ($weather_data) {
        echo '<div class="weather-widget">';
        echo '<div class="weather-current">';
        echo '<div class="weather-location">' . esc_html($weather_data['location']) . '</div>';
        echo '<div class="weather-temp">' . round($weather_data['temp']) . '°' . ($units == 'metric' ? 'C' : 'F') . '</div>';
        echo '<div class="weather-desc">' . esc_html($weather_data['description']) . '</div>';
        echo '<img src="' . esc_url($weather_data['icon']) . '" alt="' . esc_attr($weather_data['description']) . '" class="weather-icon">';
        echo '</div>';
        
        if (isset($instance['show_forecast']) && $instance['show_forecast']) {
            echo '<div class="weather-forecast">';
            foreach ($weather_data['forecast'] as $day) {
                echo '<div class="weather-day">';
                echo '<div class="weather-day-name">' . esc_html($day['day']) . '</div>';
                echo '<img src="' . esc_url($day['icon']) . '" alt="" class="weather-day-icon">';
                echo '<div class="weather-day-temp">' . round($day['temp_max']) . '°</div>';
                echo '</div>';
            }
            echo '</div>';
        }
        echo '</div>';
    } else {
        echo '<p>无法获取天气信息</p>';
    }
    
    echo $args['after_widget'];
}

public function form($instance) {
    $title = isset($instance['title']) ? $instance['title'] : '当地天气';
    $location = isset($instance['location']) ? $instance['location'] : '北京';
    $units = isset($instance['units']) ? $instance['units'] : 'metric';
    $show_forecast = isset($instance['show_forecast']) ? (bool) $instance['show_forecast'] : false;
    ?>
    <p>
        <label for="<?php echo $this->get_field_id('title'); ?>">标题:</label>
        <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" 
               name="<?php echo $this->get_field_name('title'); ?>" type="text" 
               value="<?php echo esc_attr($title); ?>">
    </p>
    <p>
        <label for="<?php echo $this->get_field_id('location'); ?>">城市:</label>
        <input class="widefat" id="<?php echo $this->get_field_id('location'); ?>" 
               name="<?php echo $this->get_field_name('location'); ?>" type="text" 
               value="<?php echo esc_attr($location); ?>">
    </p>
    <p>
        <label for="<?php echo $this->get_field_id('units'); ?>">温度单位:</label>
        <select class="widefat" id="<?php echo $this->get_field_id('units'); ?>" 
                name="<?php echo $this->get_field_name('units'); ?>">
            <option value="metric" <?php selected($units, 'metric'); ?>>摄氏度 (°C)</option>
            <option value="imperial" <?php selected($units, 'imperial'); ?>>华氏度 (°F)</option>
        </select>
    </p>
    <p>
        <input class="checkbox" type="checkbox" 
               id="<?php echo $this->get_field_id('show_forecast'); ?>"
               name="<?php echo $this->get_field_name('show_forecast'); ?>"
               <?php checked($show_forecast); ?>>
        <label for="<?php echo $this->get_field_id('show_forecast'); ?>">显示天气预报</label>
    </p>
    <?php
}

public function update($new_instance, $old_instance) {
    $instance = [];
    $instance['title'] = (!empty($new_instance['title'])) ? strip_tags($new_instance['title']) : '';
    $instance['location'] = (!empty($new_instance['location'])) ? strip_tags($new_instance['location']) : '北京';
    $instance['units'] = (!empty($new_instance['units'])) ? $new_instance['units'] : 'metric';
    $instance['show_forecast'] = isset($new_instance['show_forecast']) ? (bool) $new_instance['show_forecast'] : false;
    return $instance;
}

private function get_weather_data($location, $units) {
    if (empty($this->api_key)) {
        return false;
    }
    
    $transient_key = 'weather_data_' . md5($location . $units);
    $cached_data = get_transient($transient_key);
    
    if ($cached_data !== false) {
        return $cached_data;
    }
    
    // 使用OpenWeatherMap API
    $api_url = 'https://api.openweathermap.org/data/2.5/weather';
    $api_url .= '?q=' . urlencode($location);
    $api_url .= '&units=' . $units;
    $api_url .= '&appid=' . $this->api_key;
    $api_url .= '&lang=zh_cn';
    
    $response = wp_remote_get($api_url, [
        'timeout' => 10,
        'sslverify' => false
    ]);
    
    if (is_wp_error($response)) {
        return false;
    }
    
    $body = wp_remote_retrieve_body($response);
    $data = json_decode($body, true);
    
    if (empty($data) || isset($data['cod']) && $data['cod'] != 200) {
        return false;
    }
    
    $weather_data = [
        'location' => $data['name'] . ', ' . $data['sys']['country'],
        'temp' => $data['main']['temp'],
        'description' => $data['weather'][0]['description'],
        'icon' => 'https://openweathermap.org/img/wn/' . $data['weather'][0]['icon'] . '@2x.png',
        'forecast' => []
    ];
    
    // 获取天气预报
    $forecast_url = 'https://api.openweathermap.org/data/2.5/forecast';
    $forecast_url .= '?q=' . urlencode($location);
    $forecast_url .= '&units=' . $units;
    $forecast_url .= '&appid=' . $this->api_key;
    $forecast_url .= '&cnt=5';
    
    $forecast_response = wp_remote_get($forecast_url, [
        'timeout' => 10,
        'sslverify' => false
    ]);
    
    if (!is_wp_error($forecast_response)) {
        $forecast_body = wp_remote_retrieve_body($forecast_response);
        $forecast_data = json_decode($forecast_body, true);
        
        if (isset($forecast_data['list'])) {
            $days = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
            $count = 0;
            
            foreach ($forecast_data['list'] as $item) {
                if ($count >= 3) break;
                
                $date = new DateTime('@' . $item['dt']);
                $weather_data['forecast'][] = [
                    'day' => $days[$date->format('w')],
                    'temp_max' => $item['main']['temp_max'],
                    'icon' => 'https://openweathermap.org/img/wn/' . $item['weather'][0]['icon'] . '.png'
                ];
                $count++;
            }
        }
    }
    
    // 缓存2小时
    set_transient($transient_key, $weather_data, 2 * HOUR_IN_SECONDS);
    
    return $weather_data;
}

}

// 注册天气小工具
function register_weather_widget() {

register_widget('Weather_Widget');

}
add_action('widgets_init', 'register_weather_widget');

// 添加天气API设置字段
function add_weather_api_settings() {

if (function_exists('acf_add_local_field_group')) {
    acf_add_local_field_group([
        'key' => 'group_weather_settings',
        'title' => '天气API设置',
        'fields' => [
            [
                'key' => 'field_weather_api_key',
                'label' => 'OpenWeatherMap API密钥',
                'name' => 'weather_api_key',
                'type' => 'text',
                'instructions' => '从https://openweathermap.org/api获取API密钥',
                'required' => 0,
            ]
        ],
        'location' => [
            [
                [
                    'param' => 'options_page',
                    'operator' => '==',
                    'value' => '网站工具设置',
                ],
            ],
        ],
    ]);
}

}
add_action('acf/init', 'add_weather_api_settings');


### 3.4 创建社交媒体分享小工具

实现一个智能社交媒体分享小工具:

// 在functions.php中添加
class Social_Share_Widget extends WP_Widget {

private $platforms = [
    'facebook' => ['name' => 'Facebook', 'color' => '#1877F2'],
    'twitter' => ['name' => 'Twitter', 'color' => '#1DA1F2'],
    'linkedin' => ['name' => 'LinkedIn', 'color' => '#0077B5'],
    'weibo' => ['name' => '微博', 'color' => '#E6162D'],
    'wechat' => ['name' => '微信', 'color' => '#07C160'],
    'qq' => ['name' => 'QQ', 'color' => '#12B7F5'],
];

public function __construct() {
    parent::__construct(
        'social_share_widget',
        '社交媒体分享',
        ['description' => '添加社交媒体分享按钮']
    );
}

public function widget($args, $instance) {
    if (!is_single() && !is_page()) {
        return;
    }
    
    $title = apply_filters('widget_title', $instance['title']);
    $layout = isset($instance['layout']) ? $instance['layout'] : 'horizontal';
    $show_count = isset($instance['show_count']) ? $instance['show_count'] : false;
    
    echo $args['before_widget'];
    
    if (!empty($title)) {
        echo $args['before_title'] . $title . $args['after_title'];
    }
    
    $current_url = urlencode(get_permalink());
    $current_title = urlencode(get_the_title());
    $current_ex
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/5066.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

发表回复

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

工作时间:周一至周五,9:00-17:30,节假日休息
返回顶部