首页 / 应用软件 / WordPress REST API 开发教程,集成第三方数据服务

WordPress REST API 开发教程,集成第三方数据服务

WordPress REST API 开发教程:集成第三方数据服务,实现常用互联网小工具功能

引言:WordPress REST API 的强大潜力

WordPress作为全球最流行的内容管理系统,早已超越了简单的博客平台定位。随着REST API的全面集成,WordPress已经演变为一个功能强大的应用程序框架。本教程将深入探讨如何利用WordPress REST API进行二次开发,集成第三方数据服务,实现各种实用的互联网小工具功能。

通过本教程,您将学习到如何将WordPress转变为一个灵活的开发平台,创建诸如天气预报显示、实时汇率转换、社交媒体聚合、新闻资讯展示等实用功能。这些技能不仅适用于个人网站定制,也为企业级应用开发提供了坚实基础。

第一章:WordPress REST API 基础与配置

1.1 REST API 核心概念

WordPress REST API提供了一套标准的HTTP端点,允许开发者以JSON格式与WordPress数据进行交互。这种架构使得前端与后端分离成为可能,也为集成外部服务提供了便利。

REST API的核心优势包括:

  • 标准化数据交换格式(JSON)
  • 无状态通信,易于扩展
  • 支持多种HTTP方法(GET、POST、PUT、DELETE)
  • 完善的认证和权限控制

1.2 环境配置与基础测试

在开始开发前,确保您的WordPress版本在4.7以上,这是REST API完全集成的最低要求。您可以通过以下步骤验证REST API是否正常工作:

  1. 访问 https://您的网站域名/wp-json/,应该能看到API的索引页面
  2. 安装并激活"WP REST API Controller"等插件,方便管理API端点
  3. 使用Postman或Insomnia等API测试工具进行基础调用测试

1.3 自定义端点基础结构

创建自定义REST API端点是扩展WordPress功能的关键。以下是一个基础的自定义端点示例:

// 在主题的functions.php或自定义插件中添加
add_action('rest_api_init', function () {
    // 注册自定义路由
    register_rest_route('custom/v1', '/test', array(
        'methods' => 'GET',
        'callback' => 'custom_api_test',
        'permission_callback' => '__return_true'
    ));
});

function custom_api_test($request) {
    return new WP_REST_Response(array(
        'status' => 'success',
        'message' => '自定义API端点工作正常',
        'timestamp' => current_time('timestamp')
    ), 200);
}

第二章:第三方数据服务集成策略

2.1 选择合适的数据服务API

在集成第三方服务前,需要考虑以下因素:

  • API的稳定性和可靠性
  • 请求频率限制和定价策略
  • 数据格式的兼容性
  • 文档完整性和技术支持

常用免费数据服务包括:

  • 天气数据:OpenWeatherMap,WeatherAPI
  • 金融数据:ExchangeRate-API,Alpha Vantage
  • 新闻资讯:NewsAPI,Currents API
  • 地理位置:IP-API,OpenCage Geocoder

2.2 API密钥管理与安全

安全存储和管理API密钥至关重要。推荐做法:

// 使用WordPress选项API存储API密钥
class API_Key_Manager {
    private $api_keys;
    
    public function __construct() {
        $this->api_keys = get_option('third_party_api_keys', array());
    }
    
    public function get_key($service_name) {
        if (isset($this->api_keys[$service_name])) {
            return $this->api_keys[$service_name];
        }
        return false;
    }
    
    public function update_key($service_name, $key) {
        $this->api_keys[$service_name] = $key;
        update_option('third_party_api_keys', $this->api_keys);
    }
    
    public function create_settings_page() {
        // 创建管理页面供用户输入API密钥
        add_options_page(
            'API密钥管理',
            'API密钥',
            'manage_options',
            'api-key-settings',
            array($this, 'render_settings_page')
        );
    }
    
    public function render_settings_page() {
        // 设置页面HTML
        ?>
        <div class="wrap">
            <h1>第三方API密钥管理</h1>
            <form method="post" action="options.php">
                <?php settings_fields('api_keys_group'); ?>
                <table class="form-table">
                    <tr>
                        <th scope="row">天气API密钥</th>
                        <td>
                            <input type="text" name="weather_api_key" 
                                   value="<?php echo esc_attr($this->get_key('weather')); ?>" 
                                   class="regular-text">
                        </td>
                    </tr>
                    <!-- 更多API密钥字段 -->
                </table>
                <?php submit_button(); ?>
            </form>
        </div>
        <?php
    }
}

2.3 数据缓存与性能优化

频繁调用第三方API会影响网站性能,合理的缓存策略必不可少:

class API_Cache_Manager {
    private $cache_duration;
    
    public function __construct($duration = 3600) {
        $this->cache_duration = $duration;
    }
    
    public function get_cached_data($key) {
        $cached = get_transient($key);
        if ($cached !== false) {
            return $cached;
        }
        return false;
    }
    
    public function set_cached_data($key, $data, $duration = null) {
        $duration = $duration ?: $this->cache_duration;
        set_transient($key, $data, $duration);
    }
    
    public function fetch_with_cache($cache_key, $callback, $force_refresh = false) {
        // 强制刷新时跳过缓存
        if ($force_refresh) {
            delete_transient($cache_key);
        }
        
        // 尝试从缓存获取
        $cached_data = $this->get_cached_data($cache_key);
        if ($cached_data !== false) {
            return $cached_data;
        }
        
        // 缓存未命中,执行回调获取数据
        $fresh_data = call_user_func($callback);
        
        // 存储到缓存
        if ($fresh_data && !is_wp_error($fresh_data)) {
            $this->set_cached_data($cache_key, $fresh_data);
        }
        
        return $fresh_data;
    }
}

第三章:实用小工具开发实战

3.1 实时天气显示小工具

创建一个显示实时天气的REST API端点和小工具:

// 天气API端点
add_action('rest_api_init', function () {
    register_rest_route('tools/v1', '/weather', array(
        'methods' => 'GET',
        'callback' => 'get_weather_data',
        'permission_callback' => '__return_true',
        'args' => array(
            'city' => array(
                'required' => false,
                'default' => 'Beijing',
                'validate_callback' => function($param) {
                    return is_string($param) && !empty(trim($param));
                }
            ),
            'units' => array(
                'required' => false,
                'default' => 'metric',
                'enum' => array('metric', 'imperial')
            )
        )
    ));
});

function get_weather_data($request) {
    $city = sanitize_text_field($request->get_param('city'));
    $units = $request->get_param('units');
    
    $cache_manager = new API_Cache_Manager(1800); // 30分钟缓存
    $cache_key = 'weather_data_' . md5($city . $units);
    
    $weather_data = $cache_manager->fetch_with_cache($cache_key, function() use ($city, $units) {
        $api_manager = new API_Key_Manager();
        $api_key = $api_manager->get_key('openweathermap');
        
        if (!$api_key) {
            return new WP_Error('no_api_key', '天气API密钥未配置', array('status' => 400));
        }
        
        $api_url = sprintf(
            'https://api.openweathermap.org/data/2.5/weather?q=%s&units=%s&appid=%s',
            urlencode($city),
            $units,
            $api_key
        );
        
        $response = wp_remote_get($api_url, array('timeout' => 15));
        
        if (is_wp_error($response)) {
            return $response;
        }
        
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);
        
        if (isset($data['cod']) && $data['cod'] !== 200) {
            return new WP_Error('api_error', $data['message'] ?? '天气数据获取失败', array('status' => $data['cod']));
        }
        
        // 格式化响应数据
        return array(
            'city' => $data['name'],
            'country' => $data['sys']['country'] ?? '',
            'temperature' => round($data['main']['temp']),
            'feels_like' => round($data['main']['feels_like']),
            'humidity' => $data['main']['humidity'],
            'pressure' => $data['main']['pressure'],
            'description' => $data['weather'][0]['description'],
            'icon' => $data['weather'][0]['icon'],
            'wind_speed' => $data['wind']['speed'],
            'wind_direction' => $data['wind']['deg'] ?? 0,
            'sunrise' => date('H:i', $data['sys']['sunrise']),
            'sunset' => date('H:i', $data['sys']['sunset']),
            'timestamp' => current_time('mysql')
        );
    });
    
    return new WP_REST_Response($weather_data, 200);
}

// 天气小工具前端组件
class Weather_Widget extends WP_Widget {
    public function __construct() {
        parent::__construct(
            'weather_widget',
            '实时天气小工具',
            array('description' => '显示指定城市的实时天气信息')
        );
    }
    
    public function widget($args, $instance) {
        echo $args['before_widget'];
        
        $city = !empty($instance['city']) ? $instance['city'] : '北京';
        $units = !empty($instance['units']) ? $instance['units'] : 'metric';
        
        ?>
        <div class="weather-widget" data-city="<?php echo esc_attr($city); ?>" 
             data-units="<?php echo esc_attr($units); ?>">
            <h3 class="weather-title"><?php echo esc_html($city); ?>天气</h3>
            <div class="weather-content">
                <div class="weather-loading">加载中...</div>
            </div>
        </div>
        
        <script>
        jQuery(document).ready(function($) {
            function loadWeather() {
                var widget = $('.weather-widget');
                var city = widget.data('city');
                var units = widget.data('units');
                
                $.getJSON('/wp-json/tools/v1/weather?city=' + encodeURIComponent(city) + '&units=' + units, 
                    function(data) {
                        if (data && !data.code) {
                            var html = '<div class="weather-info">';
                            html += '<div class="weather-temp">' + data.temperature + '°' + (units === 'metric' ? 'C' : 'F') + '</div>';
                            html += '<div class="weather-desc">' + data.description + '</div>';
                            html += '<div class="weather-details">';
                            html += '<span>湿度: ' + data.humidity + '%</span>';
                            html += '<span>风速: ' + data.wind_speed + ' m/s</span>';
                            html += '</div>';
                            html += '</div>';
                            
                            widget.find('.weather-content').html(html);
                        } else {
                            widget.find('.weather-content').html('<p>天气数据暂时不可用</p>');
                        }
                    }
                ).fail(function() {
                    $('.weather-content').html('<p>天气数据加载失败</p>');
                });
            }
            
            loadWeather();
            // 每30分钟刷新一次
            setInterval(loadWeather, 30 * 60 * 1000);
        });
        </script>
        <?php
        
        echo $args['after_widget'];
    }
    
    public function form($instance) {
        $city = !empty($instance['city']) ? $instance['city'] : '';
        $units = !empty($instance['units']) ? $instance['units'] : 'metric';
        ?>
        <p>
            <label for="<?php echo $this->get_field_id('city'); ?>">城市名称:</label>
            <input class="widefat" id="<?php echo $this->get_field_id('city'); ?>" 
                   name="<?php echo $this->get_field_name('city'); ?>" 
                   type="text" value="<?php echo esc_attr($city); ?>">
        </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>
        <?php
    }
    
    public function update($new_instance, $old_instance) {
        $instance = array();
        $instance['city'] = !empty($new_instance['city']) ? sanitize_text_field($new_instance['city']) : '';
        $instance['units'] = !empty($new_instance['units']) ? sanitize_text_field($new_instance['units']) : 'metric';
        return $instance;
    }
}

// 注册小工具
add_action('widgets_init', function() {
    register_widget('Weather_Widget');
});

3.2 实时汇率转换工具

创建一个实用的汇率转换API和小工具:

// 汇率API端点
add_action('rest_api_init', function () {
    register_rest_route('tools/v1', '/exchange-rate', array(
        'methods' => 'GET',
        'callback' => 'get_exchange_rate',
        'permission_callback' => '__return_true',
        'args' => array(
            'from' => array(
                'required' => true,
                'validate_callback' => function($param) {
                    return strlen($param) === 3 && ctype_alpha($param);
                }
            ),
            'to' => array(
                'required' => true,
                'validate_callback' function($param) {
                    return strlen($param) === 3 && ctype_alpha($param);
                }
            ),
            'amount' => array(
                'required' => false,
                'default' => 1,
                'validate_callback' => function($param) {
                    return is_numeric($param) && $param >= 0;
                },
                'sanitize_callback' => 'floatval'
            )
        )
    ));
});

function get_exchange_rate($request) {
    $from = strtoupper(sanitize_text_field($request->get_param('from')));
    $to = strtoupper(sanitize_text_field($request->get_param('to')));
    $amount = floatval($request->get_param('amount'));
    
    $cache_manager = new API_Cache_Manager(3600); // 1小时缓存
    $cache_key = 'exchange_rate_' . $from . '_' . $to;
    
    $rate_data = $cache_manager->fetch_with_cache($cache_key, function() use ($from, $to) {
        // 使用ExchangeRate-API
        $api_manager = new API_Key_Manager();
        $api_key = $api_manager->get_key('exchangerate');
        
        if (!$api_key) {
            // 如果没有API密钥,使用免费替代方案
            return get_exchange_rate_fallback($from, $to);
        }
        
        $api_url = sprintf(
            'https://v6.exchangerate-api.com/v6/%s/pair/%s/%s',
            $api_key,
            $from,
            $to
        );
        
        $response = wp_remote_get($api_url, array('timeout' => 15));
        
        if (is_wp_error($response)) {
            return get_exchange_rate_fallback($from, $to);
        }
        
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);
        
        if ($data['result'] === 'success') {
            return array(
                'from' => $from,
                'to' => $to,
                'rate' => $data['conversion_rate'],
                'last_updated' => current_time('mysql'),
                'source' => 'exchangerate-api'
            );
        }
        
        return get_exchange_rate_fallback($from, $to);
    });
    
    if (is_wp_error($rate_data)) {
        return $rate_data;
    }
    
    $converted_amount = $amount * $rate_data['rate'];
    
    $response_data = array(
        'from_currency' => $from,
        'to_currency' => $to,
        'amount' => $amount,
        'exchange_rate' => $rate_data['rate'],
        'converted_amount' => round($converted_amount, 4),
        'last_updated' => $rate_data['last_updated'],
        'source' => $rate_data['source']
    );
    
    return new WP_REST_Response($response_data, 200);
}

function get_exchange_rate_fallback($from, $to) {
    // 使用免费API作为备选方案
    $api_url = sprintf(
        'https://api.exchangerate.host/latest?base=%s&symbols=%s',
        $from,
        $to
    );
    
    $response = wp_remote_get($api_url, array('timeout' => 15));
    
    if (is_wp_error($response)) {
        return new WP_Error('api_error', '无法获取汇率数据', array('status' => 500));
    }
    
    $body = wp_remote_retrieve_body($response);

$data = json_decode($body, true);


if (isset($data['rates'][$to])) {
    return array(
        'from' => $from,
        'to' => $to,
        'rate' => $data['rates'][$to],
        'last_updated' => $data['date'] . ' 00:00:00',
        'source' => 'exchangerate.host'
    );
}

return new WP_Error('no_rate', '未找到指定的汇率数据', array('status' => 404));

}

// 汇率转换小工具前端
class Currency_Converter_Widget extends WP_Widget {

private $popular_currencies = array(
    'USD' => '美元',
    'EUR' => '欧元',
    'GBP' => '英镑',
    'JPY' => '日元',
    'CNY' => '人民币',
    'CAD' => '加元',
    'AUD' => '澳元',
    'CHF' => '瑞士法郎'
);

public function __construct() {
    parent::__construct(
        'currency_converter_widget',
        '汇率转换工具',
        array('description' => '实时货币汇率转换计算器')
    );
}

public function widget($args, $instance) {
    echo $args['before_widget'];
    
    $title = !empty($instance['title']) ? $instance['title'] : '汇率转换';
    $default_from = !empty($instance['default_from']) ? $instance['default_from'] : 'USD';
    $default_to = !empty($instance['default_to']) ? $instance['default_to'] : 'CNY';
    
    ?>
    <div class="currency-converter-widget">
        <h3 class="widget-title"><?php echo esc_html($title); ?></h3>
        
        <div class="converter-form">
            <div class="input-group">
                <input type="number" class="amount-input" 
                       placeholder="金额" value="1" min="0" step="0.01">
                
                <select class="currency-select from-currency">
                    <?php foreach ($this->popular_currencies as $code => $name): ?>
                        <option value="<?php echo esc_attr($code); ?>" 
                                <?php selected($code, $default_from); ?>>
                            <?php echo esc_html("$code - $name"); ?>
                        </option>
                    <?php endforeach; ?>
                </select>
            </div>
            
            <div class="swap-button-container">
                <button type="button" class="swap-currencies">
                    <span class="dashicons dashicons-arrow-down-alt"></span>
                    <span class="dashicons dashicons-arrow-up-alt"></span>
                </button>
            </div>
            
            <div class="input-group">
                <input type="text" class="result-output" readonly 
                       placeholder="转换结果">
                
                <select class="currency-select to-currency">
                    <?php foreach ($this->popular_currencies as $code => $name): ?>
                        <option value="<?php echo esc_attr($code); ?>" 
                                <?php selected($code, $default_to); ?>>
                            <?php echo esc_html("$code - $name"); ?>
                        </option>
                    <?php endforeach; ?>
                </select>
            </div>
            
            <div class="converter-info">
                <p class="exchange-rate-info">汇率: <span class="rate-value">加载中...</span></p>
                <p class="last-updated">最后更新: <span class="update-time">-</span></p>
            </div>
            
            <button type="button" class="convert-button button button-primary">
                立即转换
            </button>
        </div>
    </div>
    
    <script>
    jQuery(document).ready(function($) {
        var converter = $('.currency-converter-widget');
        var rateInfo = converter.find('.rate-value');
        var updateTime = converter.find('.update-time');
        var resultOutput = converter.find('.result-output');
        
        function getExchangeRate(from, to, amount) {
            $.getJSON('/wp-json/tools/v1/exchange-rate?from=' + from + '&to=' + to + '&amount=' + amount, 
                function(response) {
                    if (response && !response.code) {
                        resultOutput.val(response.converted_amount.toFixed(2));
                        rateInfo.text('1 ' + response.from_currency + ' = ' + 
                                     response.exchange_rate.toFixed(4) + ' ' + response.to_currency);
                        updateTime.text(response.last_updated);
                    } else {
                        resultOutput.val('转换失败');
                        rateInfo.text('数据获取失败');
                    }
                }
            ).fail(function() {
                resultOutput.val('服务暂时不可用');
                rateInfo.text('网络错误');
            });
        }
        
        // 初始加载
        var fromCurrency = converter.find('.from-currency').val();
        var toCurrency = converter.find('.to-currency').val();
        var amount = converter.find('.amount-input').val();
        getExchangeRate(fromCurrency, toCurrency, amount);
        
        // 转换按钮点击事件
        converter.find('.convert-button').on('click', function() {
            fromCurrency = converter.find('.from-currency').val();
            toCurrency = converter.find('.to-currency').val();
            amount = converter.find('.amount-input').val();
            
            if (!amount || amount <= 0) {
                alert('请输入有效的金额');
                return;
            }
            
            getExchangeRate(fromCurrency, toCurrency, amount);
        });
        
        // 货币交换按钮
        converter.find('.swap-currencies').on('click', function() {
            var fromVal = converter.find('.from-currency').val();
            var toVal = converter.find('.to-currency').val();
            
            converter.find('.from-currency').val(toVal);
            converter.find('.to-currency').val(fromVal);
            
            // 重新获取汇率
            amount = converter.find('.amount-input').val();
            getExchangeRate(toVal, fromVal, amount);
        });
        
        // 输入框实时转换(防抖处理)
        var convertTimeout;
        converter.find('.amount-input').on('input', function() {
            clearTimeout(convertTimeout);
            convertTimeout = setTimeout(function() {
                amount = converter.find('.amount-input').val();
                if (amount && amount > 0) {
                    fromCurrency = converter.find('.from-currency').val();
                    toCurrency = converter.find('.to-currency').val();
                    getExchangeRate(fromCurrency, toCurrency, amount);
                }
            }, 500);
        });
        
        // 货币选择变化时更新
        converter.find('.currency-select').on('change', function() {
            amount = converter.find('.amount-input').val();
            if (amount && amount > 0) {
                fromCurrency = converter.find('.from-currency').val();
                toCurrency = converter.find('.to-currency').val();
                getExchangeRate(fromCurrency, toCurrency, amount);
            }
        });
    });
    </script>
    
    <style>
    .currency-converter-widget {
        padding: 15px;
        background: #f8f9fa;
        border-radius: 8px;
        border: 1px solid #dee2e6;
    }
    .converter-form .input-group {
        display: flex;
        margin-bottom: 10px;
    }
    .amount-input, .result-output, .currency-select {
        padding: 10px;
        border: 1px solid #ced4da;
        border-radius: 4px;
    }
    .amount-input {
        flex: 1;
        border-right: none;
        border-top-right-radius: 0;
        border-bottom-right-radius: 0;
    }
    .result-output {
        flex: 1;
        background: #fff;
        border-right: none;
        border-top-right-radius: 0;
        border-bottom-right-radius: 0;
    }
    .currency-select {
        width: 150px;
        border-top-left-radius: 0;
        border-bottom-left-radius: 0;
    }
    .swap-button-container {
        text-align: center;
        margin: 10px 0;
    }
    .swap-currencies {
        background: #6c757d;
        color: white;
        border: none;
        border-radius: 50%;
        width: 40px;
        height: 40px;
        cursor: pointer;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
    .swap-currencies:hover {
        background: #5a6268;
    }
    .converter-info {
        margin: 15px 0;
        font-size: 0.9em;
        color: #666;
    }
    .convert-button {
        width: 100%;
        padding: 12px;
        font-size: 16px;
    }
    </style>
    <?php
    
    echo $args['after_widget'];
}

public function form($instance) {
    $title = !empty($instance['title']) ? $instance['title'] : '汇率转换';
    $default_from = !empty($instance['default_from']) ? $instance['default_from'] : 'USD';
    $default_to = !empty($instance['default_to']) ? $instance['default_to'] : 'CNY';
    ?>
    <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('default_from'); ?>">默认源货币:</label>
        <select class="widefat" id="<?php echo $this->get_field_id('default_from'); ?>" 
                name="<?php echo $this->get_field_name('default_from'); ?>">
            <?php foreach ($this->popular_currencies as $code => $name): ?>
                <option value="<?php echo esc_attr($code); ?>" 
                        <?php selected($code, $default_from); ?>>
                    <?php echo esc_html("$code - $name"); ?>
                </option>
            <?php endforeach; ?>
        </select>
    </p>
    <p>
        <label for="<?php echo $this->get_field_id('default_to'); ?>">默认目标货币:</label>
        <select class="widefat" id="<?php echo $this->get_field_id('default_to'); ?>" 
                name="<?php echo $this->get_field_name('default_to'); ?>">
            <?php foreach ($this->popular_currencies as $code => $name): ?>
                <option value="<?php echo esc_attr($code); ?>" 
                        <?php selected($code, $default_to); ?>>
                    <?php echo esc_html("$code - $name"); ?>
                </option>
            <?php endforeach; ?>
        </select>
    </p>
    <?php
}

public function update($new_instance, $old_instance) {
    $instance = array();
    $instance['title'] = !empty($new_instance['title']) ? sanitize_text_field($new_instance['title']) : '';
    $instance['default_from'] = !empty($new_instance['default_from']) ? sanitize_text_field($new_instance['default_from']) : 'USD';
    $instance['default_to'] = !empty($new_instance['default_to']) ? sanitize_text_field($new_instance['default_to']) : 'CNY';
    return $instance;
}

}

add_action('widgets_init', function() {

register_widget('Currency_Converter_Widget');

});

第四章:社交媒体聚合与展示

4.1 Twitter/X 最新推文聚合

创建一个聚合社交媒体内容的API端点:

// Twitter API集成(使用Twitter API v2)
add_action('rest_api_init', function () {
    register_rest_route('social/v1', '/twitter/timeline', array(
        'methods' => 'GET',
        'callback' => 'get_twitter_timeline',
        'permission_callback' => '__return_true',
        'args' => array(
            'username' => array(
                'required' => false,
                'default' => '',
                'sanitize_callback' => 'sanitize_text_field'
            ),
            'count' => array(
                'required' => false,
                'default' => 5,
                'validate_callback' => function($param) {
                    return is_numeric($param) && $param > 0 && $param <= 20;
                }
            )
        )
    ));
});

function get_twitter_timeline($request) {
    $username = $request->get_param('username');
    $count = intval($request->get_param('count'));
    
    if (empty($username)) {
        $api_manager = new API_Key_Manager();
        $default_account = $api_manager->get_key('twitter_default_account');
        if ($default_account) {
            $username = $default_account;
        } else {
            return new WP_Error('no_username', '未指定Twitter用户名', array('status' => 400));
        }
    }
    
    $cache_manager = new API_Cache_Manager(300); // 5分钟缓存
    $cache_key = 'twitter_timeline_' . md5($username . $count);
    
    $tweets = $cache_manager->fetch_with_cache($cache_key, function() use ($username, $count) {
        $api_manager = new API_Key_Manager();
        $bearer_token = $api_manager->get_key('twitter_bearer_token');
        
        if (!$bearer_token) {
            // 如果没有正式API密钥,使用备用方案
            return get_twitter_timeline_fallback($username, $count);
        }
        
        // 首先获取用户ID
        $user_url = sprintf(
            'https://api.twitter.com/2/users/by/username/%s',
            urlencode($username)
        );
        
        $user_response = wp_remote_get($user_url, array(
            'timeout' => 15,
            'headers' => array(
                'Authorization' => 'Bearer ' . $bearer_token
            )
        ));
        
        if (is_wp_error($user_response)) {
            return get_twitter_timeline_fallback($username, $count);
        }
        
        $user_data = json_decode(wp_remote_retrieve_body($user_response), true);
        
        if (!isset($user_data['data']['id'])) {
            return new WP_Error('user_not_found', '未找到指定的Twitter用户', array('status' => 404));
        }
        
        $user_id = $user_data['data']['id'];
        
        // 获取用户时间线
        $timeline_url = sprintf(
            'https://api.twitter.com/2/users/%s/tweets?max_results=%d&tweet.fields=created_at,public_metrics,entities',
            $user_id,
            $count
        );
        
        $timeline_response = wp_remote_get($timeline_url, array(
            'timeout' => 15,
            'headers' => array(
                'Authorization' => 'Bearer ' . $bearer_token
            )
        ));
        
        if (is_wp_error($timeline_response)) {
            return get_twitter_timeline_fallback($username, $count);
        }
        
        $timeline_data = json_decode(wp_remote_retrieve_body($timeline_response), true);
        
        if (!isset($timeline_data['data'])) {
            return array();
        }
        
        $formatted_tweets = array();
        foreach ($timeline_data['data'] as $tweet) {
            $formatted_tweets[] = array(
                'id' => $tweet['id'],
                'text' => format_tweet_text($tweet['text'], $tweet['entities'] ?? array()),
                'created_at' => $tweet['created_at'],
                'timestamp' => strtotime($tweet['created_at']),
                'likes' => $tweet['public_metrics']['like_count'] ?? 0,
                'retweets' => $tweet['public_metrics']['retweet_count'] ?? 0,
                'replies' => $tweet['public_metrics']['reply_count'] ?? 0,
                'url' => sprintf('https://twitter.com/%s/status/%s', $username, $tweet['id'])
            );
        }
        
        return $formatted_tweets;
    });
    
    if (is_wp_error($tweets)) {
        return $tweets;
    }
    
    return new WP_REST_Response(array(
        'username' => $username,
        'tweets' => $tweets,
        'count' => count($tweets),
        'retrieved_at' => current_time('mysql')
    ), 200);
}

function format_tweet_text($text, $entities) {
    // 处理链接
    if (isset($entities['urls'])) {
        foreach ($entities['urls'] as $url) {
            $text = str_replace(
                $url['url'],
                sprintf('<a href="%s" target="_blank" rel="noopener">%s</a>', 
                       esc_url($url['expanded_url']), 
                       esc_html($url['display_url'])),
                $text
            );
        }
    }
    
    // 处理提及
    if (isset($entities['mentions'])) {
        foreach ($entities['mentions'] as $mention) {
            $text = str_replace(
                '@' . $mention['username'],
                sprintf('<a href="https://twitter.com/%s" target="_blank" rel="noopener">@%s</a>', 
                       esc_attr($mention['username']), 
                       esc_html($mention['username'])),
                $text
            );
        }
    }
    
    // 处理标签
    if (isset($entities['hashtags'])) {
        foreach ($entities['hashtags'] as $hashtag) {
            $text = str_replace(
                '#' . $hashtag['tag'],
                sprintf('<a href="https://twitter.com/hashtag/%s" target="_blank" rel="noopener">#%s</a>', 
                       esc_attr($hashtag['tag']), 
                       esc_html($hashtag['tag'])),
                $text
            );
        }
    }
    
    return $text;
}
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/5051.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

发表回复

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

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