文章目录
-
- 在当今数字化时代,企业网站已不再仅仅是展示信息的静态页面,而是需要具备智能化、自动化功能的综合平台。WordPress作为全球最受欢迎的内容管理系统,其真正的强大之处在于其高度的可扩展性和灵活性。通过代码二次开发,我们可以将WordPress从一个简单的博客平台转变为功能强大的业务工具。本教程将深入探讨如何通过WordPress程序开发,集成网站自动化社交媒体舆情监测与预警通知系统,同时实现常用互联网小工具功能,为您的网站增添智能化翅膀。
-
- 在进行WordPress二次开发前,首先需要搭建合适的开发环境。推荐使用本地开发环境如XAMPP、MAMP或Local by Flywheel,这些工具可以快速搭建包含Apache、MySQL和PHP的完整环境。对于代码编辑器,Visual Studio Code或PHPStorm都是优秀的选择,它们提供了强大的代码提示、调试和版本控制集成功能。 确保您的开发环境满足以下要求: PHP版本7.4或更高(推荐8.0+) MySQL 5.6+或MariaDB 10.1+ Apache或Nginx服务器 启用必要的PHP扩展(curl、json、mbstring等)
- 为避免直接修改主题文件导致更新时丢失更改,我们强烈建议创建子主题。在wp-content/themes目录下创建新文件夹,命名为您的主题名加“-child”,例如“twentytwentyone-child”。 子主题至少需要包含以下文件: style.css:包含主题元数据 functions.php:用于添加自定义功能 可选的模板文件 在style.css中添加: /* Theme Name: Twenty Twenty-One Child Template: twentytwentyone Version: 1.0 */
- 安装以下开发辅助插件: Query Monitor:数据库查询和性能分析 Debug Bar:PHP错误和警告显示 Show Current Template:显示当前使用的模板文件 Advanced Custom Fields:自定义字段管理(可选但推荐)
-
- 社交媒体舆情监测系统需要包含以下核心模块: 数据采集模块:从各社交媒体平台获取数据 数据处理模块:清洗、分析和分类数据 存储模块:将处理后的数据存入数据库 展示模块:在WordPress后台和前端展示数据 预警模块:根据设定规则触发通知
- 首先,我们需要集成主流社交媒体的API。以下是一个基础类,用于处理多个平台的API连接: class SocialMediaMonitor { private $platforms = []; private $api_keys = []; public function __construct() { $this->init_platforms(); } private function init_platforms() { // 从数据库或配置文件中读取API密钥 $this->api_keys = get_option('social_media_api_keys', []); // 初始化各平台连接 $this->platforms = [ 'twitter' => new TwitterAPI($this->api_keys['twitter'] ?? ''), 'facebook' => new FacebookAPI($this->api_keys['facebook'] ?? ''), 'instagram' => new InstagramAPI($this->api_keys['instagram'] ?? ''), 'weibo' => new WeiboAPI($this->api_keys['weibo'] ?? ''), ]; } public function fetch_posts($platform, $keywords, $limit = 100) { if (!isset($this->platforms[$platform])) { return new WP_Error('invalid_platform', '不支持的社交媒体平台'); } try { return $this->platforms[$platform]->search($keywords, $limit); } catch (Exception $e) { error_log('社交媒体数据获取失败: ' . $e->getMessage()); return []; } } }
- 使用WordPress的Cron系统定时采集数据: class SocialMediaCrawler { public function __construct() { add_action('init', [$this, 'schedule_crawling']); add_action('social_media_crawl_hook', [$this, 'crawl_all_platforms']); } public function schedule_crawling() { if (!wp_next_scheduled('social_media_crawl_hook')) { wp_schedule_event(time(), 'hourly', 'social_media_crawl_hook'); } } public function crawl_all_platforms() { $monitor = new SocialMediaMonitor(); $keywords = get_option('monitoring_keywords', []); foreach (['twitter', 'facebook', 'instagram'] as $platform) { $posts = $monitor->fetch_posts($platform, $keywords, 50); $this->process_and_store($posts, $platform); } // 记录最后一次爬取时间 update_option('last_crawl_time', current_time('mysql')); } private function process_and_store($posts, $platform) { global $wpdb; $table_name = $wpdb->prefix . 'social_media_posts'; foreach ($posts as $post) { $data = [ 'platform' => $platform, 'post_id' => $post['id'], 'author' => sanitize_text_field($post['author']), 'content' => wp_kses_post($post['content']), 'url' => esc_url_raw($post['url']), 'likes' => intval($post['likes']), 'shares' => intval($post['shares']), 'comments' => intval($post['comments']), 'post_time' => $post['created_at'], 'sentiment' => $this->analyze_sentiment($post['content']), 'created_at' => current_time('mysql') ]; $wpdb->insert($table_name, $data); } } }
- 集成自然语言处理功能,分析文本情感和提取关键词: class SentimentAnalyzer { private $positive_words = []; private $negative_words = []; public function __construct() { // 加载情感词典 $this->load_sentiment_dictionaries(); } public function analyze($text) { $words = $this->tokenize($text); $positive_score = 0; $negative_score = 0; foreach ($words as $word) { if (in_array($word, $this->positive_words)) { $positive_score++; } if (in_array($word, $this->negative_words)) { $negative_score++; } } $total = $positive_score + $negative_score; if ($total == 0) { return 'neutral'; } $score = ($positive_score - $negative_score) / $total; if ($score > 0.2) { return 'positive'; } elseif ($score < -0.2) { return 'negative'; } else { return 'neutral'; } } public function extract_keywords($text, $limit = 5) { // 使用TF-IDF算法或简单词频统计 $words = $this->tokenize($text); $stop_words = $this->get_stop_words(); // 过滤停用词 $filtered_words = array_diff($words, $stop_words); // 统计词频 $word_freq = array_count_values($filtered_words); // 按频率排序 arsort($word_freq); // 返回前N个关键词 return array_slice(array_keys($word_freq), 0, $limit); } }
-
- 创建灵活可配置的预警规则系统: class AlertSystem { private $rules = []; public function __construct() { $this->load_rules(); add_action('new_social_media_post', [$this, 'check_alerts'], 10, 2); } private function load_rules() { $this->rules = get_option('alert_rules', [ [ 'id' => 1, 'name' => '负面舆情预警', 'conditions' => [ 'sentiment' => 'negative', 'engagement' => '>100', 'keywords' => ['投诉', '问题', '故障'] ], 'channels' => ['email', 'slack'], 'recipients' => ['admin@example.com'], 'cooldown' => 300 // 5分钟内不重复报警 ] ]); } public function check_alerts($post_data, $platform) { foreach ($this->rules as $rule) { if ($this->matches_rule($post_data, $rule)) { $this->trigger_alert($rule, $post_data); } } } private function matches_rule($post_data, $rule) { foreach ($rule['conditions'] as $key => $value) { if (!$this->check_condition($post_data, $key, $value)) { return false; } } return true; } private function trigger_alert($rule, $post_data) { $last_alert = get_transient('alert_' . $rule['id']); if ($last_alert) { return; // 还在冷却期内 } // 发送通知到各个渠道 foreach ($rule['channels'] as $channel) { switch ($channel) { case 'email': $this->send_email_alert($rule, $post_data); break; case 'slack': $this->send_slack_alert($rule, $post_data); break; case 'webhook': $this->send_webhook_alert($rule, $post_data); break; } } // 设置冷却期 set_transient('alert_' . $rule['id'], true, $rule['cooldown']); // 记录报警历史 $this->log_alert($rule, $post_data); } }
- 实现多种通知渠道: class NotificationChannels { public function send_email($to, $subject, $message, $headers = '') { if (empty($headers)) { $headers = [ 'Content-Type: text/html; charset=UTF-8', 'From: 舆情监测系统 <alerts@yourdomain.com>' ]; } return wp_mail($to, $subject, $message, $headers); } public function send_slack($webhook_url, $message, $channel = '#alerts') { $payload = [ 'channel' => $channel, 'username' => '舆情监测机器人', 'text' => $message, 'icon_emoji' => ':warning:' ]; $args = [ 'body' => json_encode($payload), 'headers' => ['Content-Type' => 'application/json'], 'timeout' => 30 ]; return wp_remote_post($webhook_url, $args); } public function send_webhook($url, $data) { $args = [ 'body' => json_encode($data), 'headers' => ['Content-Type' => 'application/json'], 'timeout' => 30 ]; return wp_remote_post($url, $args); } public function send_sms($phone, $message) { // 集成短信服务商API $api_key = get_option('sms_api_key'); $api_url = 'https://api.sms-provider.com/send'; $data = [ 'apikey' => $api_key, 'mobile' => $phone, 'text' => $message ]; return wp_remote_post($api_url, [ 'body' => $data, 'timeout' => 30 ]); } }
- 创建实时监控仪表盘: class MonitoringDashboard { public function __construct() { add_action('admin_menu', [$this, 'add_admin_pages']); add_action('wp_dashboard_setup', [$this, 'add_dashboard_widget']); add_shortcode('social_media_monitor', [$this, 'shortcode_display']); } public function add_admin_pages() { add_menu_page( '舆情监测系统', '舆情监测', 'manage_options', 'social-media-monitor', [$this, 'render_dashboard'], 'dashicons-chart-line', 30 ); // 添加子菜单 add_submenu_page( 'social-media-monitor', '预警设置', '预警设置', 'manage_options', 'alert-settings', [$this, 'render_alert_settings'] ); } public function render_dashboard() { ?> <div class="wrap"> <h1>社交媒体舆情监测仪表盘</h1> <div class="dashboard-grid"> <div class="dashboard-card"> <h3>今日舆情概览</h3> <div id="sentiment-chart"></div> </div> <div class="dashboard-card"> <h3>平台分布</h3> <div id="platform-chart"></div> </div> <div class="dashboard-card full-width"> <h3>实时动态</h3> <div id="realtime-feed"></div> </div> </div> <script> // 使用Chart.js或ECharts渲染图表 </script> </div> <?php } public function add_dashboard_widget() { wp_add_dashboard_widget( 'social_media_widget', '社交媒体舆情监控', [$this, 'render_dashboard_widget'] ); } public function shortcode_display($atts) { $atts = shortcode_atts([ 'platform' => 'all', 'limit' => 10, 'show_sentiment' => true ], $atts); ob_start(); $this->render_public_display($atts); return ob_get_clean(); } }
-
- 创建通用工具类,集成常用功能: class WordPressTools { // URL缩短功能 public static function shorten_url($url, $service = 'bitly') { $api_keys = get_option('url_shortener_keys', []); switch ($service) { case 'bitly': return $this->bitly_shorten($url, $api_keys['bitly'] ?? ''); case 'tinyurl': return $this->tinyurl_shorten($url); default: return $url; } } // 二维码生成 public static function generate_qrcode($data, $size = 200) { $api_url = 'https://api.qrserver.com/v1/create-qr-code/'; return add_query_arg([ 'data' => urlencode($data), 'size' => $size . 'x' . $size ], $api_url); } // 内容摘要生成 public static function generate_excerpt($content, $length = 200) { $content = strip_tags($content); $content = preg_replace('/s+/', ' ', $content); if (mb_strlen($content) <= $length) { return $content; } return mb_substr($content, 0, $length) . '...'; } // 图片压缩与优化 public static function optimize_image($image_url, $quality = 80) { // 使用WordPress图像处理API $upload_dir = wp_upload_dir(); $image_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $image_url); if (file_exists($image_path)) { $editor = wp_get_image_editor($image_path); if (!is_wp_error($editor)) { $editor->set_quality($quality); $result = $editor->save(); if (!is_wp_error($result)) { return str_replace($upload_dir['basedir'], $upload_dir['baseurl'], $result['path']); } } } return $image_url; } }
- 创建易于使用的短代码和小工具: class ToolShortcodes { public function __construct() { // 注册短代码 add_shortcode('qrcode', [$this, 'qrcode_shortcode']); add_shortcode('countdown', [$this, 'countdown_shortcode']); add_shortcode('weather', [$this, 'weather_shortcode']); add_shortcode('calculator', [$this, 'calculator_shortcode']); // 注册小工具 add_action('widgets_init', [$this, 'register_widgets']); } public function qrcode_shortcode($atts) { $atts = shortcode_atts([ 'data' => get_permalink(), 'size' => '150', 'color' => '000000', 'bgcolor' => 'ffffff' ], $atts); $url = 'https://api.qrserver.com/v1/create-qr-code/'; $params = [ 'data' => $atts['data'], 'size' => $atts['size'] . 'x' . $atts['size'], 'color' => $atts['color'], 'bgcolor' => $atts['bgcolor'] ]; $src = add_query_arg($params, $url); return sprintf(
- // 天气小工具类 class WeatherWidget extends WP_Widget { public function __construct() { parent::__construct( 'weather_widget', '实时天气', ['description' => '显示当前位置的实时天气信息'] ); } public function widget($args, $instance) { echo $args['before_widget']; if (!empty($instance['title'])) { echo $args['before_title'] . apply_filters('widget_title', $instance['title']) . $args['after_title']; } $location = !empty($instance['location']) ? $instance['location'] : 'auto'; $units = !empty($instance['units']) ? $instance['units'] : 'metric'; $weather_data = $this->get_weather_data($location, $units); if ($weather_data) { ?> <div class="weather-widget"> <div class="weather-current"> <div class="weather-icon"> <img src="<?php echo esc_url($weather_data['icon']); ?>" alt="<?php echo esc_attr($weather_data['description']); ?>"> </div> <div class="weather-temp"> <span class="temp-number"><?php echo round($weather_data['temp']); ?></span> <span class="temp-unit">°<?php echo $units === 'metric' ? 'C' : 'F'; ?></span> </div> <div class="weather-details"> <p class="weather-desc"><?php echo esc_html($weather_data['description']); ?></p> <p class="weather-location"><?php echo esc_html($weather_data['location']); ?></p> <div class="weather-extra"> <span>湿度: <?php echo $weather_data['humidity']; ?>%</span> <span>风速: <?php echo $weather_data['wind_speed']; ?> km/h</span> </div> </div> </div> <?php if (!empty($weather_data['forecast'])) : ?> <div class="weather-forecast"> <?php foreach (array_slice($weather_data['forecast'], 0, 5) as $day) : ?> <div class="forecast-day"> <span class="day-name"><?php echo $day['day']; ?></span> <img src="<?php echo esc_url($day['icon']); ?>" alt="<?php echo esc_attr($day['desc']); ?>"> <span class="day-temp"><?php echo round($day['temp_max']); ?>°</span> </div> <?php endforeach; ?> </div> <?php endif; ?> </div> <?php } else { echo '<p>无法获取天气数据</p>'; } echo $args['after_widget']; } private function get_weather_data($location, $units) { $api_key = get_option('weather_api_key', ''); $cache_key = 'weather_data_' . md5($location . $units); $cached_data = get_transient($cache_key); if ($cached_data !== false) { return $cached_data; } if (empty($api_key)) { return false; } $api_url = 'https://api.openweathermap.org/data/2.5/weather'; if ($location === 'auto') { // 尝试获取用户IP位置 $ip = $_SERVER['REMOTE_ADDR']; $geo_data = wp_remote_get("http://ip-api.com/json/{$ip}"); if (!is_wp_error($geo_data)) { $geo = json_decode(wp_remote_retrieve_body($geo_data), true); if ($geo && $geo['status'] === 'success') { $location = "{$geo['lat']},{$geo['lon']}"; } } } $params = [ 'q' => $location, 'appid' => $api_key, 'units' => $units, 'lang' => 'zh_cn' ]; $response = wp_remote_get(add_query_arg($params, $api_url)); if (is_wp_error($response)) { return false; } $data = json_decode(wp_remote_retrieve_body($response), true); if ($data && $data['cod'] == 200) { $weather_data = [ 'location' => $data['name'] . ', ' . $data['sys']['country'], 'temp' => $data['main']['temp'], 'humidity' => $data['main']['humidity'], 'pressure' => $data['main']['pressure'], 'wind_speed' => $data['wind']['speed'], 'description' => $data['weather'][0]['description'], 'icon' => "https://openweathermap.org/img/wn/{$data['weather'][0]['icon']}@2x.png", 'forecast' => $this->get_forecast($data['coord']['lat'], $data['coord']['lon'], $api_key, $units) ]; // 缓存1小时 set_transient($cache_key, $weather_data, HOUR_IN_SECONDS); return $weather_data; } return false; } } // 计算器短代码实现 public function calculator_shortcode($atts) { $atts = shortcode_atts([ 'type' => 'basic', 'theme' => 'light', 'currency' => 'CNY' ], $atts); ob_start(); ?> <div class="calculator-container" data-theme="<?php echo esc_attr($atts['theme']); ?>"> <?php if ($atts['type'] === 'basic') : ?> <div class="calculator basic-calculator"> <div class="calculator-display"> <input type="text" readonly value="0" class="calc-display"> </div> <div class="calculator-buttons"> <button class="calc-btn operator" data-action="clear">C</button> <button class="calc-btn operator" data-action="backspace">⌫</button> <button class="calc-btn operator" data-action="percentage">%</button> <button class="calc-btn operator" data-action="divide">÷</button> <button class="calc-btn number" data-number="7">7</button> <button class="calc-btn number" data-number="8">8</button> <button class="calc-btn number" data-number="9">9</button> <button class="calc-btn operator" data-action="multiply">×</button> <button class="calc-btn number" data-number="4">4</button> <button class="calc-btn number" data-number="5">5</button> <button class="calc-btn number" data-number="6">6</button> <button class="calc-btn operator" data-action="subtract">-</button> <button class="calc-btn number" data-number="1">1</button> <button class="calc-btn number" data-number="2">2</button> <button class="calc-btn number" data-number="3">3</button> <button class="calc-btn operator" data-action="add">+</button> <button class="calc-btn number zero" data-number="0">0</button> <button class="calc-btn number" data-number=".">.</button> <button class="calc-btn operator equals" data-action="equals">=</button> </div> </div> <?php elseif ($atts['type'] === 'currency') : ?> <div class="calculator currency-converter"> <div class="converter-row"> <input type="number" class="amount-input" value="1" min="0" step="0.01"> <select class="currency-select from-currency"> <option value="CNY">人民币 (CNY)</option> <option value="USD">美元 (USD)</option> <option value="EUR">欧元 (EUR)</option> <option value="JPY">日元 (JPY)</option> <option value="GBP">英镑 (GBP)</option> </select> </div> <div class="converter-swap"> <button class="swap-btn">⇅</button> </div> <div class="converter-row"> <input type="number" class="amount-output" readonly> <select class="currency-select to-currency"> <option value="USD">美元 (USD)</option> <option value="CNY">人民币 (CNY)</option> <option value="EUR">欧元 (EUR)</option> <option value="JPY">日元 (JPY)</option> <option value="GBP">英镑 (GBP)</option> </select> </div> <div class="converter-rate"> 汇率: <span class="rate-value">1 CNY = 0.14 USD</span> <span class="rate-update">更新时间: <span class="update-time"></span></span> </div> </div> <?php endif; ?> </div> <script> (function($) { 'use strict'; <?php if ($atts['type'] === 'basic') : ?> // 基础计算器逻辑 $(document).ready(function() { let currentInput = '0'; let previousInput = ''; let operation = null; let resetScreen = false; $('.basic-calculator .calc-display').val(currentInput); $('.calc-btn.number').on('click', function() { const number = $(this).data('number'); if (currentInput === '0' || resetScreen) { currentInput = number; resetScreen = false; } else { currentInput += number; } $('.calc-display').val(currentInput); }); $('.calc-btn.operator').on('click', function() { const action = $(this).data('action'); switch(action) { case 'clear': currentInput = '0'; previousInput = ''; operation = null; break; case 'backspace': if (currentInput.length > 1) { currentInput = currentInput.slice(0, -1); } else { currentInput = '0'; } break; case 'percentage': currentInput = (parseFloat(currentInput) / 100).toString(); break; case 'add': case 'subtract': case 'multiply': case 'divide': if (previousInput !== '') { calculate(); } operation = action; previousInput = currentInput; resetScreen = true; break; case 'equals': if (previousInput !== '' && operation !== null) { calculate(); operation = null; previousInput = ''; } break; } $('.calc-display').val(currentInput); }); function calculate() { let prev = parseFloat(previousInput); let current = parseFloat(currentInput); let result = 0; switch(operation) { case 'add': result = prev + current; break; case 'subtract': result = prev - current; break; case 'multiply': result = prev * current; break; case 'divide': result = current !== 0 ? prev / current : '错误'; break; } currentInput = result.toString(); resetScreen = true; } }); <?php elseif ($atts['type'] === 'currency') : ?> // 货币转换器逻辑 $(document).ready(function() { const apiKey = '<?php echo get_option('currency_api_key', ''); ?>'; let exchangeRates = {}; let lastUpdate = null; function updateExchangeRates() { if (!apiKey) { // 使用免费API $.getJSON('https://api.exchangerate-api.com/v4/latest/CNY') .done(function(data) { exchangeRates = data.rates; lastUpdate = new Date(data.date); updateDisplay(); }) .fail(function() { // 备用数据源 loadFallbackRates(); }); } else { // 使用付费API $.ajax({ url: 'https://api.currencyapi.com/v3/latest', headers: { 'apikey': apiKey }, success: function(data) { exchangeRates = data.data; lastUpdate = new Date(data.meta.last_updated_at); updateDisplay(); } }); } } function loadFallbackRates() { // 硬编码的汇率(示例数据) exchangeRates = { 'CNY': 1, 'USD': 0.14, 'EUR': 0.13, 'JPY': 15.5, 'GBP': 0.11 }; lastUpdate = new Date(); updateDisplay(); } function updateDisplay() { const fromCurrency = $('.from-currency').val(); const toCurrency = $('.to-currency').val(); const amount = parseFloat($('.amount-input').val()); if (exchangeRates[fromCurrency] && exchangeRates[toCurrency]) { const rate = exchangeRates[toCurrency] / exchangeRates[fromCurrency]; const converted = amount * rate; $('.amount-output').val(converted.toFixed(2)); $('.rate-value').text(`1 ${fromCurrency} = ${rate.toFixed(4)} ${toCurrency}`); $('.update-time').text(lastUpdate.toLocaleTimeString()); } } // 初始化 updateExchangeRates(); // 事件监听 $('.amount-input, .from-currency, .to-currency').on('input change', updateDisplay); $('.swap-btn').on('click', function() { const fromVal = $('.from-currency').val(); const toVal = $('.to-currency').val(); $('.from-currency').val(toVal); $('.to-currency').val(fromVal); updateDisplay(); }); // 每30分钟更新一次汇率 setInterval(updateExchangeRates, 30 * 60 * 1000); }); <?php endif; ?> })(jQuery); </script> <style> .calculator-container { max-width: 400px; margin: 20px auto; border-radius: 10px; overflow: hidden; box-shadow: 0 4px 12px rgba(0,0,0,0.1); } .basic-calculator { background: #f5f5f5; padding: 20px; } .calculator-display { margin-bottom: 20px; } .calc-display { width: 100%; height: 60px; font-size: 24px; text-align: right; padding: 10px; border: none; background: white; border-radius: 5px; box-shadow: inset 0 2px 5px rgba(0,0,0,0.1); } .calculator-buttons { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; } .calc-btn { height: 50px; font-size: 18px; border: none; border-radius: 5px; cursor: pointer; transition: all 0.2s; } .calc-btn.number { background: white; color: #333; } .calc-btn.operator { background: #4a90e2; color: white; } .calc-btn.equals { background: #f39c12; color: white; } .calc-btn.zero { grid-column: span 2; } .calc-btn:hover { opacity: 0.9; transform: translateY(-2px); } .currency-converter { background: white; padding: 20px; } .converter-row { display: flex; gap: 10px; margin-bottom: 15px; } .amount-input, .amount-output { flex: 1; height: 50px; font-size: 18px; padding: 10px; border: 1px solid #ddd; border-radius: 5px; } .currency-select { width: 150px; height: 50px; font-size: 16px; padding: 10px; border: 1px solid #ddd; border-radius: 5px; } .converter-swap { text-align: center; margin: 10px 0; } .swap-btn { width: 40px; height: 40px; border-radius: 50%; border: 2px solid #4a90e2; background: white; color: #4a90e2; font-size: 18px; cursor: pointer; transition: all 0.2s; } .swap-btn:hover { background: #4a90e2; color: white; } .converter-rate { margin-top: 20px; padding-top: 15px; border-top: 1px solid #eee; font-size: 14px; color: #666; } .rate-value { font-weight: bold; color: #333; } .rate-update { float: right; } </style> <?php return ob_get_clean(); }
在当今数字化时代,企业网站已不再仅仅是展示信息的静态页面,而是需要具备智能化、自动化功能的综合平台。WordPress作为全球最受欢迎的内容管理系统,其真正的强大之处在于其高度的可扩展性和灵活性。通过代码二次开发,我们可以将WordPress从一个简单的博客平台转变为功能强大的业务工具。本教程将深入探讨如何通过WordPress程序开发,集成网站自动化社交媒体舆情监测与预警通知系统,同时实现常用互联网小工具功能,为您的网站增添智能化翅膀。
在进行WordPress二次开发前,首先需要搭建合适的开发环境。推荐使用本地开发环境如XAMPP、MAMP或Local by Flywheel,这些工具可以快速搭建包含Apache、MySQL和PHP的完整环境。对于代码编辑器,Visual Studio Code或PHPStorm都是优秀的选择,它们提供了强大的代码提示、调试和版本控制集成功能。
确保您的开发环境满足以下要求:
- PHP版本7.4或更高(推荐8.0+)
- MySQL 5.6+或MariaDB 10.1+
- Apache或Nginx服务器
- 启用必要的PHP扩展(curl、json、mbstring等)
为避免直接修改主题文件导致更新时丢失更改,我们强烈建议创建子主题。在wp-content/themes目录下创建新文件夹,命名为您的主题名加“-child”,例如“twentytwentyone-child”。
子主题至少需要包含以下文件:
- style.css:包含主题元数据
- functions.php:用于添加自定义功能
- 可选的模板文件
在style.css中添加:
/*
Theme Name: Twenty Twenty-One Child
Template: twentytwentyone
Version: 1.0
*/
安装以下开发辅助插件:
- Query Monitor:数据库查询和性能分析
- Debug Bar:PHP错误和警告显示
- Show Current Template:显示当前使用的模板文件
- Advanced Custom Fields:自定义字段管理(可选但推荐)
社交媒体舆情监测系统需要包含以下核心模块:
- 数据采集模块:从各社交媒体平台获取数据
- 数据处理模块:清洗、分析和分类数据
- 存储模块:将处理后的数据存入数据库
- 展示模块:在WordPress后台和前端展示数据
- 预警模块:根据设定规则触发通知
首先,我们需要集成主流社交媒体的API。以下是一个基础类,用于处理多个平台的API连接:
class SocialMediaMonitor {
private $platforms = [];
private $api_keys = [];
public function __construct() {
$this->init_platforms();
}
private function init_platforms() {
// 从数据库或配置文件中读取API密钥
$this->api_keys = get_option('social_media_api_keys', []);
// 初始化各平台连接
$this->platforms = [
'twitter' => new TwitterAPI($this->api_keys['twitter'] ?? ''),
'facebook' => new FacebookAPI($this->api_keys['facebook'] ?? ''),
'instagram' => new InstagramAPI($this->api_keys['instagram'] ?? ''),
'weibo' => new WeiboAPI($this->api_keys['weibo'] ?? ''),
];
}
public function fetch_posts($platform, $keywords, $limit = 100) {
if (!isset($this->platforms[$platform])) {
return new WP_Error('invalid_platform', '不支持的社交媒体平台');
}
try {
return $this->platforms[$platform]->search($keywords, $limit);
} catch (Exception $e) {
error_log('社交媒体数据获取失败: ' . $e->getMessage());
return [];
}
}
}
使用WordPress的Cron系统定时采集数据:
class SocialMediaCrawler {
public function __construct() {
add_action('init', [$this, 'schedule_crawling']);
add_action('social_media_crawl_hook', [$this, 'crawl_all_platforms']);
}
public function schedule_crawling() {
if (!wp_next_scheduled('social_media_crawl_hook')) {
wp_schedule_event(time(), 'hourly', 'social_media_crawl_hook');
}
}
public function crawl_all_platforms() {
$monitor = new SocialMediaMonitor();
$keywords = get_option('monitoring_keywords', []);
foreach (['twitter', 'facebook', 'instagram'] as $platform) {
$posts = $monitor->fetch_posts($platform, $keywords, 50);
$this->process_and_store($posts, $platform);
}
// 记录最后一次爬取时间
update_option('last_crawl_time', current_time('mysql'));
}
private function process_and_store($posts, $platform) {
global $wpdb;
$table_name = $wpdb->prefix . 'social_media_posts';
foreach ($posts as $post) {
$data = [
'platform' => $platform,
'post_id' => $post['id'],
'author' => sanitize_text_field($post['author']),
'content' => wp_kses_post($post['content']),
'url' => esc_url_raw($post['url']),
'likes' => intval($post['likes']),
'shares' => intval($post['shares']),
'comments' => intval($post['comments']),
'post_time' => $post['created_at'],
'sentiment' => $this->analyze_sentiment($post['content']),
'created_at' => current_time('mysql')
];
$wpdb->insert($table_name, $data);
}
}
}
集成自然语言处理功能,分析文本情感和提取关键词:
class SentimentAnalyzer {
private $positive_words = [];
private $negative_words = [];
public function __construct() {
// 加载情感词典
$this->load_sentiment_dictionaries();
}
public function analyze($text) {
$words = $this->tokenize($text);
$positive_score = 0;
$negative_score = 0;
foreach ($words as $word) {
if (in_array($word, $this->positive_words)) {
$positive_score++;
}
if (in_array($word, $this->negative_words)) {
$negative_score++;
}
}
$total = $positive_score + $negative_score;
if ($total == 0) {
return 'neutral';
}
$score = ($positive_score - $negative_score) / $total;
if ($score > 0.2) {
return 'positive';
} elseif ($score < -0.2) {
return 'negative';
} else {
return 'neutral';
}
}
public function extract_keywords($text, $limit = 5) {
// 使用TF-IDF算法或简单词频统计
$words = $this->tokenize($text);
$stop_words = $this->get_stop_words();
// 过滤停用词
$filtered_words = array_diff($words, $stop_words);
// 统计词频
$word_freq = array_count_values($filtered_words);
// 按频率排序
arsort($word_freq);
// 返回前N个关键词
return array_slice(array_keys($word_freq), 0, $limit);
}
}
创建灵活可配置的预警规则系统:
class AlertSystem {
private $rules = [];
public function __construct() {
$this->load_rules();
add_action('new_social_media_post', [$this, 'check_alerts'], 10, 2);
}
private function load_rules() {
$this->rules = get_option('alert_rules', [
[
'id' => 1,
'name' => '负面舆情预警',
'conditions' => [
'sentiment' => 'negative',
'engagement' => '>100',
'keywords' => ['投诉', '问题', '故障']
],
'channels' => ['email', 'slack'],
'recipients' => ['admin@example.com'],
'cooldown' => 300 // 5分钟内不重复报警
]
]);
}
public function check_alerts($post_data, $platform) {
foreach ($this->rules as $rule) {
if ($this->matches_rule($post_data, $rule)) {
$this->trigger_alert($rule, $post_data);
}
}
}
private function matches_rule($post_data, $rule) {
foreach ($rule['conditions'] as $key => $value) {
if (!$this->check_condition($post_data, $key, $value)) {
return false;
}
}
return true;
}
private function trigger_alert($rule, $post_data) {
$last_alert = get_transient('alert_' . $rule['id']);
if ($last_alert) {
return; // 还在冷却期内
}
// 发送通知到各个渠道
foreach ($rule['channels'] as $channel) {
switch ($channel) {
case 'email':
$this->send_email_alert($rule, $post_data);
break;
case 'slack':
$this->send_slack_alert($rule, $post_data);
break;
case 'webhook':
$this->send_webhook_alert($rule, $post_data);
break;
}
}
// 设置冷却期
set_transient('alert_' . $rule['id'], true, $rule['cooldown']);
// 记录报警历史
$this->log_alert($rule, $post_data);
}
}
实现多种通知渠道:
class NotificationChannels {
public function send_email($to, $subject, $message, $headers = '') {
if (empty($headers)) {
$headers = [
'Content-Type: text/html; charset=UTF-8',
'From: 舆情监测系统 <alerts@yourdomain.com>'
];
}
return wp_mail($to, $subject, $message, $headers);
}
public function send_slack($webhook_url, $message, $channel = '#alerts') {
$payload = [
'channel' => $channel,
'username' => '舆情监测机器人',
'text' => $message,
'icon_emoji' => ':warning:'
];
$args = [
'body' => json_encode($payload),
'headers' => ['Content-Type' => 'application/json'],
'timeout' => 30
];
return wp_remote_post($webhook_url, $args);
}
public function send_webhook($url, $data) {
$args = [
'body' => json_encode($data),
'headers' => ['Content-Type' => 'application/json'],
'timeout' => 30
];
return wp_remote_post($url, $args);
}
public function send_sms($phone, $message) {
// 集成短信服务商API
$api_key = get_option('sms_api_key');
$api_url = 'https://api.sms-provider.com/send';
$data = [
'apikey' => $api_key,
'mobile' => $phone,
'text' => $message
];
return wp_remote_post($api_url, [
'body' => $data,
'timeout' => 30
]);
}
}
创建实时监控仪表盘:
class MonitoringDashboard {
public function __construct() {
add_action('admin_menu', [$this, 'add_admin_pages']);
add_action('wp_dashboard_setup', [$this, 'add_dashboard_widget']);
add_shortcode('social_media_monitor', [$this, 'shortcode_display']);
}
public function add_admin_pages() {
add_menu_page(
'舆情监测系统',
'舆情监测',
'manage_options',
'social-media-monitor',
[$this, 'render_dashboard'],
'dashicons-chart-line',
30
);
// 添加子菜单
add_submenu_page(
'social-media-monitor',
'预警设置',
'预警设置',
'manage_options',
'alert-settings',
[$this, 'render_alert_settings']
);
}
public function render_dashboard() {
?>
<div class="wrap">
<h1>社交媒体舆情监测仪表盘</h1>
<div class="dashboard-grid">
<div class="dashboard-card">
<h3>今日舆情概览</h3>
<div id="sentiment-chart"></div>
</div>
<div class="dashboard-card">
<h3>平台分布</h3>
<div id="platform-chart"></div>
</div>
<div class="dashboard-card full-width">
<h3>实时动态</h3>
<div id="realtime-feed"></div>
</div>
</div>
<script>
// 使用Chart.js或ECharts渲染图表
</script>
</div>
<?php
}
public function add_dashboard_widget() {
wp_add_dashboard_widget(
'social_media_widget',
'社交媒体舆情监控',
[$this, 'render_dashboard_widget']
);
}
public function shortcode_display($atts) {
$atts = shortcode_atts([
'platform' => 'all',
'limit' => 10,
'show_sentiment' => true
], $atts);
ob_start();
$this->render_public_display($atts);
return ob_get_clean();
}
}
创建通用工具类,集成常用功能:
class WordPressTools {
// URL缩短功能
public static function shorten_url($url, $service = 'bitly') {
$api_keys = get_option('url_shortener_keys', []);
switch ($service) {
case 'bitly':
return $this->bitly_shorten($url, $api_keys['bitly'] ?? '');
case 'tinyurl':
return $this->tinyurl_shorten($url);
default:
return $url;
}
}
// 二维码生成
public static function generate_qrcode($data, $size = 200) {
$api_url = 'https://api.qrserver.com/v1/create-qr-code/';
return add_query_arg([
'data' => urlencode($data),
'size' => $size . 'x' . $size
], $api_url);
}
// 内容摘要生成
public static function generate_excerpt($content, $length = 200) {
$content = strip_tags($content);
$content = preg_replace('/s+/', ' ', $content);
if (mb_strlen($content) <= $length) {
return $content;
}
return mb_substr($content, 0, $length) . '...';
}
// 图片压缩与优化
public static function optimize_image($image_url, $quality = 80) {
// 使用WordPress图像处理API
$upload_dir = wp_upload_dir();
$image_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $image_url);
if (file_exists($image_path)) {
$editor = wp_get_image_editor($image_path);
if (!is_wp_error($editor)) {
$editor->set_quality($quality);
$result = $editor->save();
if (!is_wp_error($result)) {
return str_replace($upload_dir['basedir'], $upload_dir['baseurl'], $result['path']);
}
}
}
return $image_url;
}
}
创建易于使用的短代码和小工具:
class ToolShortcodes {
public function __construct() {
// 注册短代码
add_shortcode('qrcode', [$this, 'qrcode_shortcode']);
add_shortcode('countdown', [$this, 'countdown_shortcode']);
add_shortcode('weather', [$this, 'weather_shortcode']);
add_shortcode('calculator', [$this, 'calculator_shortcode']);
// 注册小工具
add_action('widgets_init', [$this, 'register_widgets']);
}
public function qrcode_shortcode($atts) {
$atts = shortcode_atts([
'data' => get_permalink(),
'size' => '150',
'color' => '000000',
'bgcolor' => 'ffffff'
], $atts);
$url = 'https://api.qrserver.com/v1/create-qr-code/';
$params = [
'data' => $atts['data'],
'size' => $atts['size'] . 'x' . $atts['size'],
'color' => $atts['color'],
'bgcolor' => $atts['bgcolor']
];
$src = add_query_arg($params, $url);
return sprintf(
// 天气小工具类
class WeatherWidget extends WP_Widget {
public function __construct() {
parent::__construct(
'weather_widget',
'实时天气',
['description' => '显示当前位置的实时天气信息']
);
}
public function widget($args, $instance) {
echo $args['before_widget'];
if (!empty($instance['title'])) {
echo $args['before_title'] . apply_filters('widget_title', $instance['title']) . $args['after_title'];
}
$location = !empty($instance['location']) ? $instance['location'] : 'auto';
$units = !empty($instance['units']) ? $instance['units'] : 'metric';
$weather_data = $this->get_weather_data($location, $units);
if ($weather_data) {
?>
<div class="weather-widget">
<div class="weather-current">
<div class="weather-icon">
<img src="<?php echo esc_url($weather_data['icon']); ?>"
alt="<?php echo esc_attr($weather_data['description']); ?>">
</div>
<div class="weather-temp">
<span class="temp-number"><?php echo round($weather_data['temp']); ?></span>
<span class="temp-unit">°<?php echo $units === 'metric' ? 'C' : 'F'; ?></span>
</div>
<div class="weather-details">
<p class="weather-desc"><?php echo esc_html($weather_data['description']); ?></p>
<p class="weather-location"><?php echo esc_html($weather_data['location']); ?></p>
<div class="weather-extra">
<span>湿度: <?php echo $weather_data['humidity']; ?>%</span>
<span>风速: <?php echo $weather_data['wind_speed']; ?> km/h</span>
</div>
</div>
</div>
<?php if (!empty($weather_data['forecast'])) : ?>
<div class="weather-forecast">
<?php foreach (array_slice($weather_data['forecast'], 0, 5) as $day) : ?>
<div class="forecast-day">
<span class="day-name"><?php echo $day['day']; ?></span>
<img src="<?php echo esc_url($day['icon']); ?>" alt="<?php echo esc_attr($day['desc']); ?>">
<span class="day-temp"><?php echo round($day['temp_max']); ?>°</span>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<?php
} else {
echo '<p>无法获取天气数据</p>';
}
echo $args['after_widget'];
}
private function get_weather_data($location, $units) {
$api_key = get_option('weather_api_key', '');
$cache_key = 'weather_data_' . md5($location . $units);
$cached_data = get_transient($cache_key);
if ($cached_data !== false) {
return $cached_data;
}
if (empty($api_key)) {
return false;
}
$api_url = 'https://api.openweathermap.org/data/2.5/weather';
if ($location === 'auto') {
// 尝试获取用户IP位置
$ip = $_SERVER['REMOTE_ADDR'];
$geo_data = wp_remote_get("http://ip-api.com/json/{$ip}");
if (!is_wp_error($geo_data)) {
$geo = json_decode(wp_remote_retrieve_body($geo_data), true);
if ($geo && $geo['status'] === 'success') {
$location = "{$geo['lat']},{$geo['lon']}";
}
}
}
$params = [
'q' => $location,
'appid' => $api_key,
'units' => $units,
'lang' => 'zh_cn'
];
$response = wp_remote_get(add_query_arg($params, $api_url));
if (is_wp_error($response)) {
return false;
}
$data = json_decode(wp_remote_retrieve_body($response), true);
if ($data && $data['cod'] == 200) {
$weather_data = [
'location' => $data['name'] . ', ' . $data['sys']['country'],
'temp' => $data['main']['temp'],
'humidity' => $data['main']['humidity'],
'pressure' => $data['main']['pressure'],
'wind_speed' => $data['wind']['speed'],
'description' => $data['weather'][0]['description'],
'icon' => "https://openweathermap.org/img/wn/{$data['weather'][0]['icon']}@2x.png",
'forecast' => $this->get_forecast($data['coord']['lat'], $data['coord']['lon'], $api_key, $units)
];
// 缓存1小时
set_transient($cache_key, $weather_data, HOUR_IN_SECONDS);
return $weather_data;
}
return false;
}
}
// 计算器短代码实现
public function calculator_shortcode($atts) {
$atts = shortcode_atts([
'type' => 'basic',
'theme' => 'light',
'currency' => 'CNY'
], $atts);
ob_start();
?>
<div class="calculator-container" data-theme="<?php echo esc_attr($atts['theme']); ?>">
<?php if ($atts['type'] === 'basic') : ?>
<div class="calculator basic-calculator">
<div class="calculator-display">
<input type="text" readonly value="0" class="calc-display">
</div>
<div class="calculator-buttons">
<button class="calc-btn operator" data-action="clear">C</button>
<button class="calc-btn operator" data-action="backspace">⌫</button>
<button class="calc-btn operator" data-action="percentage">%</button>
<button class="calc-btn operator" data-action="divide">÷</button>
<button class="calc-btn number" data-number="7">7</button>
<button class="calc-btn number" data-number="8">8</button>
<button class="calc-btn number" data-number="9">9</button>
<button class="calc-btn operator" data-action="multiply">×</button>
<button class="calc-btn number" data-number="4">4</button>
<button class="calc-btn number" data-number="5">5</button>
<button class="calc-btn number" data-number="6">6</button>
<button class="calc-btn operator" data-action="subtract">-</button>
<button class="calc-btn number" data-number="1">1</button>
<button class="calc-btn number" data-number="2">2</button>
<button class="calc-btn number" data-number="3">3</button>
<button class="calc-btn operator" data-action="add">+</button>
<button class="calc-btn number zero" data-number="0">0</button>
<button class="calc-btn number" data-number=".">.</button>
<button class="calc-btn operator equals" data-action="equals">=</button>
</div>
</div>
<?php elseif ($atts['type'] === 'currency') : ?>
<div class="calculator currency-converter">
<div class="converter-row">
<input type="number" class="amount-input" value="1" min="0" step="0.01">
<select class="currency-select from-currency">
<option value="CNY">人民币 (CNY)</option>
<option value="USD">美元 (USD)</option>
<option value="EUR">欧元 (EUR)</option>
<option value="JPY">日元 (JPY)</option>
<option value="GBP">英镑 (GBP)</option>
</select>
</div>
<div class="converter-swap">
<button class="swap-btn">⇅</button>
</div>
<div class="converter-row">
<input type="number" class="amount-output" readonly>
<select class="currency-select to-currency">
<option value="USD">美元 (USD)</option>
<option value="CNY">人民币 (CNY)</option>
<option value="EUR">欧元 (EUR)</option>
<option value="JPY">日元 (JPY)</option>
<option value="GBP">英镑 (GBP)</option>
</select>
</div>
<div class="converter-rate">
汇率: <span class="rate-value">1 CNY = 0.14 USD</span>
<span class="rate-update">更新时间: <span class="update-time"></span></span>
</div>
</div>
<?php endif; ?>
</div>
<script>
(function($) {
'use strict';
<?php if ($atts['type'] === 'basic') : ?>
// 基础计算器逻辑
$(document).ready(function() {
let currentInput = '0';
let previousInput = '';
let operation = null;
let resetScreen = false;
$('.basic-calculator .calc-display').val(currentInput);
$('.calc-btn.number').on('click', function() {
const number = $(this).data('number');
if (currentInput === '0' || resetScreen) {
currentInput = number;
resetScreen = false;
} else {
currentInput += number;
}
$('.calc-display').val(currentInput);
});
$('.calc-btn.operator').on('click', function() {
const action = $(this).data('action');
switch(action) {
case 'clear':
currentInput = '0';
previousInput = '';
operation = null;
break;
case 'backspace':
if (currentInput.length > 1) {
currentInput = currentInput.slice(0, -1);
} else {
currentInput = '0';
}
break;
case 'percentage':
currentInput = (parseFloat(currentInput) / 100).toString();
break;
case 'add':
case 'subtract':
case 'multiply':
case 'divide':
if (previousInput !== '') {
calculate();
}
operation = action;
previousInput = currentInput;
resetScreen = true;
break;
case 'equals':
if (previousInput !== '' && operation !== null) {
calculate();
operation = null;
previousInput = '';
}
break;
}
$('.calc-display').val(currentInput);
});
function calculate() {
let prev = parseFloat(previousInput);
let current = parseFloat(currentInput);
let result = 0;
switch(operation) {
case 'add':
result = prev + current;
break;
case 'subtract':
result = prev - current;
break;
case 'multiply':
result = prev * current;
break;
case 'divide':
result = current !== 0 ? prev / current : '错误';
break;
}
currentInput = result.toString();
resetScreen = true;
}
});
<?php elseif ($atts['type'] === 'currency') : ?>
// 货币转换器逻辑
$(document).ready(function() {
const apiKey = '<?php echo get_option('currency_api_key', ''); ?>';
let exchangeRates = {};
let lastUpdate = null;
function updateExchangeRates() {
if (!apiKey) {
// 使用免费API
$.getJSON('https://api.exchangerate-api.com/v4/latest/CNY')
.done(function(data) {
exchangeRates = data.rates;
lastUpdate = new Date(data.date);
updateDisplay();
})
.fail(function() {
// 备用数据源
loadFallbackRates();
});
} else {
// 使用付费API
$.ajax({
url: 'https://api.currencyapi.com/v3/latest',
headers: { 'apikey': apiKey },
success: function(data) {
exchangeRates = data.data;
lastUpdate = new Date(data.meta.last_updated_at);
updateDisplay();
}
});
}
}
function loadFallbackRates() {
// 硬编码的汇率(示例数据)
exchangeRates = {
'CNY': 1,
'USD': 0.14,
'EUR': 0.13,
'JPY': 15.5,
'GBP': 0.11
};
lastUpdate = new Date();
updateDisplay();
}
function updateDisplay() {
const fromCurrency = $('.from-currency').val();
const toCurrency = $('.to-currency').val();
const amount = parseFloat($('.amount-input').val());
if (exchangeRates[fromCurrency] && exchangeRates[toCurrency]) {
const rate = exchangeRates[toCurrency] / exchangeRates[fromCurrency];
const converted = amount * rate;
$('.amount-output').val(converted.toFixed(2));
$('.rate-value').text(`1 ${fromCurrency} = ${rate.toFixed(4)} ${toCurrency}`);
$('.update-time').text(lastUpdate.toLocaleTimeString());
}
}
// 初始化
updateExchangeRates();
// 事件监听
$('.amount-input, .from-currency, .to-currency').on('input change', updateDisplay);
$('.swap-btn').on('click', function() {
const fromVal = $('.from-currency').val();
const toVal = $('.to-currency').val();
$('.from-currency').val(toVal);
$('.to-currency').val(fromVal);
updateDisplay();
});
// 每30分钟更新一次汇率
setInterval(updateExchangeRates, 30 * 60 * 1000);
});
<?php endif; ?>
})(jQuery);
</script>
<style>
.calculator-container {
max-width: 400px;
margin: 20px auto;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.basic-calculator {
background: #f5f5f5;
padding: 20px;
}
.calculator-display {
margin-bottom: 20px;
}
.calc-display {
width: 100%;
height: 60px;
font-size: 24px;
text-align: right;
padding: 10px;
border: none;
background: white;
border-radius: 5px;
box-shadow: inset 0 2px 5px rgba(0,0,0,0.1);
}
.calculator-buttons {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
}
.calc-btn {
height: 50px;
font-size: 18px;
border: none;
border-radius: 5px;
cursor: pointer;
transition: all 0.2s;
}
.calc-btn.number {
background: white;
color: #333;
}
.calc-btn.operator {
background: #4a90e2;
color: white;
}
.calc-btn.equals {
background: #f39c12;
color: white;
}
.calc-btn.zero {
grid-column: span 2;
}
.calc-btn:hover {
opacity: 0.9;
transform: translateY(-2px);
}
.currency-converter {
background: white;
padding: 20px;
}
.converter-row {
display: flex;
gap: 10px;
margin-bottom: 15px;
}
.amount-input, .amount-output {
flex: 1;
height: 50px;
font-size: 18px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
.currency-select {
width: 150px;
height: 50px;
font-size: 16px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
.converter-swap {
text-align: center;
margin: 10px 0;
}
.swap-btn {
width: 40px;
height: 40px;
border-radius: 50%;
border: 2px solid #4a90e2;
background: white;
color: #4a90e2;
font-size: 18px;
cursor: pointer;
transition: all 0.2s;
}
.swap-btn:hover {
background: #4a90e2;
color: white;
}
.converter-rate {
margin-top: 20px;
padding-top: 15px;
border-top: 1px solid #eee;
font-size: 14px;
color: #666;
}
.rate-value {
font-weight: bold;
color: #333;
}
.rate-update {
float: right;
}
</style>
<?php
return ob_get_clean();
}
// 天气小工具类
class WeatherWidget extends WP_Widget {
public function __construct() {
parent::__construct(
'weather_widget',
'实时天气',
['description' => '显示当前位置的实时天气信息']
);
}
public function widget($args, $instance) {
echo $args['before_widget'];
if (!empty($instance['title'])) {
echo $args['before_title'] . apply_filters('widget_title', $instance['title']) . $args['after_title'];
}
$location = !empty($instance['location']) ? $instance['location'] : 'auto';
$units = !empty($instance['units']) ? $instance['units'] : 'metric';
$weather_data = $this->get_weather_data($location, $units);
if ($weather_data) {
?>
<div class="weather-widget">
<div class="weather-current">
<div class="weather-icon">
<img src="<?php echo esc_url($weather_data['icon']); ?>"
alt="<?php echo esc_attr($weather_data['description']); ?>">
</div>
<div class="weather-temp">
<span class="temp-number"><?php echo round($weather_data['temp']); ?></span>
<span class="temp-unit">°<?php echo $units === 'metric' ? 'C' : 'F'; ?></span>
</div>
<div class="weather-details">
<p class="weather-desc"><?php echo esc_html($weather_data['description']); ?></p>
<p class="weather-location"><?php echo esc_html($weather_data['location']); ?></p>
<div class="weather-extra">
<span>湿度: <?php echo $weather_data['humidity']; ?>%</span>
<span>风速: <?php echo $weather_data['wind_speed']; ?> km/h</span>
</div>
</div>
</div>
<?php if (!empty($weather_data['forecast'])) : ?>
<div class="weather-forecast">
<?php foreach (array_slice($weather_data['forecast'], 0, 5) as $day) : ?>
<div class="forecast-day">
<span class="day-name"><?php echo $day['day']; ?></span>
<img src="<?php echo esc_url($day['icon']); ?>" alt="<?php echo esc_attr($day['desc']); ?>">
<span class="day-temp"><?php echo round($day['temp_max']); ?>°</span>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<?php
} else {
echo '<p>无法获取天气数据</p>';
}
echo $args['after_widget'];
}
private function get_weather_data($location, $units) {
$api_key = get_option('weather_api_key', '');
$cache_key = 'weather_data_' . md5($location . $units);
$cached_data = get_transient($cache_key);
if ($cached_data !== false) {
return $cached_data;
}
if (empty($api_key)) {
return false;
}
$api_url = 'https://api.openweathermap.org/data/2.5/weather';
if ($location === 'auto') {
// 尝试获取用户IP位置
$ip = $_SERVER['REMOTE_ADDR'];
$geo_data = wp_remote_get("http://ip-api.com/json/{$ip}");
if (!is_wp_error($geo_data)) {
$geo = json_decode(wp_remote_retrieve_body($geo_data), true);
if ($geo && $geo['status'] === 'success') {
$location = "{$geo['lat']},{$geo['lon']}";
}
}
}
$params = [
'q' => $location,
'appid' => $api_key,
'units' => $units,
'lang' => 'zh_cn'
];
$response = wp_remote_get(add_query_arg($params, $api_url));
if (is_wp_error($response)) {
return false;
}
$data = json_decode(wp_remote_retrieve_body($response), true);
if ($data && $data['cod'] == 200) {
$weather_data = [
'location' => $data['name'] . ', ' . $data['sys']['country'],
'temp' => $data['main']['temp'],
'humidity' => $data['main']['humidity'],
'pressure' => $data['main']['pressure'],
'wind_speed' => $data['wind']['speed'],
'description' => $data['weather'][0]['description'],
'icon' => "https://openweathermap.org/img/wn/{$data['weather'][0]['icon']}@2x.png",
'forecast' => $this->get_forecast($data['coord']['lat'], $data['coord']['lon'], $api_key, $units)
];
// 缓存1小时
set_transient($cache_key, $weather_data, HOUR_IN_SECONDS);
return $weather_data;
}
return false;
}
}
// 计算器短代码实现
public function calculator_shortcode($atts) {
$atts = shortcode_atts([
'type' => 'basic',
'theme' => 'light',
'currency' => 'CNY'
], $atts);
ob_start();
?>
<div class="calculator-container" data-theme="<?php echo esc_attr($atts['theme']); ?>">
<?php if ($atts['type'] === 'basic') : ?>
<div class="calculator basic-calculator">
<div class="calculator-display">
<input type="text" readonly value="0" class="calc-display">
</div>
<div class="calculator-buttons">
<button class="calc-btn operator" data-action="clear">C</button>
<button class="calc-btn operator" data-action="backspace">⌫</button>
<button class="calc-btn operator" data-action="percentage">%</button>
<button class="calc-btn operator" data-action="divide">÷</button>
<button class="calc-btn number" data-number="7">7</button>
<button class="calc-btn number" data-number="8">8</button>
<button class="calc-btn number" data-number="9">9</button>
<button class="calc-btn operator" data-action="multiply">×</button>
<button class="calc-btn number" data-number="4">4</button>
<button class="calc-btn number" data-number="5">5</button>
<button class="calc-btn number" data-number="6">6</button>
<button class="calc-btn operator" data-action="subtract">-</button>
<button class="calc-btn number" data-number="1">1</button>
<button class="calc-btn number" data-number="2">2</button>
<button class="calc-btn number" data-number="3">3</button>
<button class="calc-btn operator" data-action="add">+</button>
<button class="calc-btn number zero" data-number="0">0</button>
<button class="calc-btn number" data-number=".">.</button>
<button class="calc-btn operator equals" data-action="equals">=</button>
</div>
</div>
<?php elseif ($atts['type'] === 'currency') : ?>
<div class="calculator currency-converter">
<div class="converter-row">
<input type="number" class="amount-input" value="1" min="0" step="0.01">
<select class="currency-select from-currency">
<option value="CNY">人民币 (CNY)</option>
<option value="USD">美元 (USD)</option>
<option value="EUR">欧元 (EUR)</option>
<option value="JPY">日元 (JPY)</option>
<option value="GBP">英镑 (GBP)</option>
</select>
</div>
<div class="converter-swap">
<button class="swap-btn">⇅</button>
</div>
<div class="converter-row">
<input type="number" class="amount-output" readonly>
<select class="currency-select to-currency">
<option value="USD">美元 (USD)</option>
<option value="CNY">人民币 (CNY)</option>
<option value="EUR">欧元 (EUR)</option>
<option value="JPY">日元 (JPY)</option>
<option value="GBP">英镑 (GBP)</option>
</select>
</div>
<div class="converter-rate">
汇率: <span class="rate-value">1 CNY = 0.14 USD</span>
<span class="rate-update">更新时间: <span class="update-time"></span></span>
</div>
</div>
<?php endif; ?>
</div>
<script>
(function($) {
'use strict';
<?php if ($atts['type'] === 'basic') : ?>
// 基础计算器逻辑
$(document).ready(function() {
let currentInput = '0';
let previousInput = '';
let operation = null;
let resetScreen = false;
$('.basic-calculator .calc-display').val(currentInput);
$('.calc-btn.number').on('click', function() {
const number = $(this).data('number');
if (currentInput === '0' || resetScreen) {
currentInput = number;
resetScreen = false;
} else {
currentInput += number;
}
$('.calc-display').val(currentInput);
});
$('.calc-btn.operator').on('click', function() {
const action = $(this).data('action');
switch(action) {
case 'clear':
currentInput = '0';
previousInput = '';
operation = null;
break;
case 'backspace':
if (currentInput.length > 1) {
currentInput = currentInput.slice(0, -1);
} else {
currentInput = '0';
}
break;
case 'percentage':
currentInput = (parseFloat(currentInput) / 100).toString();
break;
case 'add':
case 'subtract':
case 'multiply':
case 'divide':
if (previousInput !== '') {
calculate();
}
operation = action;
previousInput = currentInput;
resetScreen = true;
break;
case 'equals':
if (previousInput !== '' && operation !== null) {
calculate();
operation = null;
previousInput = '';
}
break;
}
$('.calc-display').val(currentInput);
});
function calculate() {
let prev = parseFloat(previousInput);
let current = parseFloat(currentInput);
let result = 0;
switch(operation) {
case 'add':
result = prev + current;
break;
case 'subtract':
result = prev - current;
break;
case 'multiply':
result = prev * current;
break;
case 'divide':
result = current !== 0 ? prev / current : '错误';
break;
}
currentInput = result.toString();
resetScreen = true;
}
});
<?php elseif ($atts['type'] === 'currency') : ?>
// 货币转换器逻辑
$(document).ready(function() {
const apiKey = '<?php echo get_option('currency_api_key', ''); ?>';
let exchangeRates = {};
let lastUpdate = null;
function updateExchangeRates() {
if (!apiKey) {
// 使用免费API
$.getJSON('https://api.exchangerate-api.com/v4/latest/CNY')
.done(function(data) {
exchangeRates = data.rates;
lastUpdate = new Date(data.date);
updateDisplay();
})
.fail(function() {
// 备用数据源
loadFallbackRates();
});
} else {
// 使用付费API
$.ajax({
url: 'https://api.currencyapi.com/v3/latest',
headers: { 'apikey': apiKey },
success: function(data) {
exchangeRates = data.data;
lastUpdate = new Date(data.meta.last_updated_at);
updateDisplay();
}
});
}
}
function loadFallbackRates() {
// 硬编码的汇率(示例数据)
exchangeRates = {
'CNY': 1,
'USD': 0.14,
'EUR': 0.13,
'JPY': 15.5,
'GBP': 0.11
};
lastUpdate = new Date();
updateDisplay();
}
function updateDisplay() {
const fromCurrency = $('.from-currency').val();
const toCurrency = $('.to-currency').val();
const amount = parseFloat($('.amount-input').val());
if (exchangeRates[fromCurrency] && exchangeRates[toCurrency]) {
const rate = exchangeRates[toCurrency] / exchangeRates[fromCurrency];
const converted = amount * rate;
$('.amount-output').val(converted.toFixed(2));
$('.rate-value').text(`1 ${fromCurrency} = ${rate.toFixed(4)} ${toCurrency}`);
$('.update-time').text(lastUpdate.toLocaleTimeString());
}
}
// 初始化
updateExchangeRates();
// 事件监听
$('.amount-input, .from-currency, .to-currency').on('input change', updateDisplay);
$('.swap-btn').on('click', function() {
const fromVal = $('.from-currency').val();
const toVal = $('.to-currency').val();
$('.from-currency').val(toVal);
$('.to-currency').val(fromVal);
updateDisplay();
});
// 每30分钟更新一次汇率
setInterval(updateExchangeRates, 30 * 60 * 1000);
});
<?php endif; ?>
})(jQuery);
</script>
<style>
.calculator-container {
max-width: 400px;
margin: 20px auto;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.basic-calculator {
background: #f5f5f5;
padding: 20px;
}
.calculator-display {
margin-bottom: 20px;
}
.calc-display {
width: 100%;
height: 60px;
font-size: 24px;
text-align: right;
padding: 10px;
border: none;
background: white;
border-radius: 5px;
box-shadow: inset 0 2px 5px rgba(0,0,0,0.1);
}
.calculator-buttons {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
}
.calc-btn {
height: 50px;
font-size: 18px;
border: none;
border-radius: 5px;
cursor: pointer;
transition: all 0.2s;
}
.calc-btn.number {
background: white;
color: #333;
}
.calc-btn.operator {
background: #4a90e2;
color: white;
}
.calc-btn.equals {
background: #f39c12;
color: white;
}
.calc-btn.zero {
grid-column: span 2;
}
.calc-btn:hover {
opacity: 0.9;
transform: translateY(-2px);
}
.currency-converter {
background: white;
padding: 20px;
}
.converter-row {
display: flex;
gap: 10px;
margin-bottom: 15px;
}
.amount-input, .amount-output {
flex: 1;
height: 50px;
font-size: 18px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
.currency-select {
width: 150px;
height: 50px;
font-size: 16px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
.converter-swap {
text-align: center;
margin: 10px 0;
}
.swap-btn {
width: 40px;
height: 40px;
border-radius: 50%;
border: 2px solid #4a90e2;
background: white;
color: #4a90e2;
font-size: 18px;
cursor: pointer;
transition: all 0.2s;
}
.swap-btn:hover {
background: #4a90e2;
color: white;
}
.converter-rate {
margin-top: 20px;
padding-top: 15px;
border-top: 1px solid #eee;
font-size: 14px;
color: #666;
}
.rate-value {
font-weight: bold;
color: #333;
}
.rate-update {
float: right;
}
</style>
<?php
return ob_get_clean();
}


