文章目录[隐藏]
详细教程:集成网站实时在线聊天与通讯应用,通过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 创建开发子主题
为了避免直接修改主题文件导致更新时丢失更改,我们首先创建一个子主题:
- 在WordPress的
wp-content/themes/目录下创建新文件夹,命名为my-custom-theme - 在该文件夹中创建
style.css文件,添加以下内容:
/*
Theme Name: My Custom Theme
Template: twentytwentythree // 根据您使用的父主题修改
Version: 1.0.0
Description: 自定义主题,用于集成实时聊天功能
*/
/* 导入父主题样式 */
@import url("../twentytwentythree/style.css");
- 创建
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 安装必要插件
我们将使用一些插件作为基础,然后通过代码扩展功能:
- Advanced Custom Fields (ACF) - 用于创建自定义设置页面
- Query Monitor - 开发调试工具(可选但推荐)
第二部分:构建实时聊天系统
2.1 实时通讯技术选型
实现实时通讯有多种技术方案:
- WebSocket:全双工通信,实时性最好
- Server-Sent Events (SSE):服务器向客户端推送消息
- 长轮询:兼容性好但效率较低
- 第三方服务集成:如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服务器:
-
通过Composer安装Ratchet:
composer require cboden/ratchet - 创建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
