文章目录
-
- 在当今数字化时代,网站已不仅仅是信息展示的窗口,更是功能集成与服务的平台。WordPress作为全球最受欢迎的内容管理系统,占据了互联网上超过43%的网站份额。然而,许多用户仅将其视为简单的博客或内容发布工具,未能充分挖掘其作为强大开发平台的潜力。 实际上,通过代码二次开发,WordPress可以转型为功能丰富的应用平台,集成自动化数据采集、信息聚合以及各种实用小工具。本教程将深入探讨如何通过WordPress开发,实现网站自动化数据采集与信息聚合,并集成常用互联网小工具功能,帮助您将普通网站升级为智能化的多功能平台。
-
- 在开始WordPress二次开发之前,首先需要搭建合适的开发环境。推荐使用本地开发环境如XAMPP、MAMP或Local by Flywheel,这些工具提供了完整的PHP、MySQL和Web服务器环境。 对于代码编辑器,Visual Studio Code是目前最受欢迎的选择,配合以下扩展插件可极大提升开发效率: PHP Intelephense(PHP代码智能提示) WordPress Snippet(WordPress代码片段) GitLens(Git版本控制集成) 此外,建议安装调试工具如Query Monitor和Debug Bar,这些插件能帮助您在开发过程中实时监控数据库查询、PHP错误和性能数据。
- 要有效进行WordPress二次开发,必须深入理解其核心架构: 主题系统:WordPress主题控制网站的外观和显示方式。子主题开发是自定义功能而不影响父主题更新的最佳实践。创建子主题只需在wp-content/themes目录下建立新文件夹,包含style.css和functions.php文件。 插件系统:插件用于扩展WordPress功能,独立于主题。良好的插件应遵循单一职责原则,专注于特定功能的实现。 钩子机制:动作钩子(Action Hooks)和过滤器钩子(Filter Hooks)是WordPress扩展性的核心。动作钩子允许在特定点执行自定义代码,而过滤器钩子允许修改数据。 // 动作钩子示例 add_action('wp_head', 'custom_head_code'); function custom_head_code() { echo '<meta name="custom-tag" content="value">'; } // 过滤器钩子示例 add_filter('the_title', 'custom_title_format'); function custom_title_format($title) { return '📌 ' . $title; }
- 对于数据采集和聚合,自定义文章类型(CPT)和字段是基础。CPT允许您创建不同于标准文章和页面的内容类型,如“新闻”、“产品”或“数据条目”。 // 注册自定义文章类型 function register_data_collection_cpt() { $labels = array( 'name' => '采集数据', 'singular_name' => '数据条目' ); $args = array( 'labels' => $labels, 'public' => true, 'has_archive' => true, 'supports' => array('title', 'editor', 'custom-fields'), 'show_in_rest' => true, // 启用Gutenberg编辑器支持 ); register_post_type('collected_data', $args); } add_action('init', 'register_data_collection_cpt'); 对于更复杂的字段需求,推荐使用Advanced Custom Fields(ACF)插件或Meta Box框架,它们提供了直观的字段管理界面。
-
- 在开发数据采集功能前,需要明确采集目标、数据源和更新频率。常见的数据源包括: RSS/Atom订阅源 公开API接口 网页抓取(需遵守robots.txt和法律法规) 社交媒体平台 公开数据库 设计数据采集系统时,应考虑以下因素: 数据源稳定性与可用性 采集频率与服务器负载平衡 数据去重与更新机制 错误处理与日志记录 版权与法律合规性
- WordPress提供了内置的定时任务系统WP-Cron,可用于定期执行数据采集任务。但需要注意的是,WP-Cron基于页面访问触发,对于精确的定时任务可能不够可靠。对于高要求的采集任务,建议使用系统级的Cron任务。 // 注册定时采集任务 function register_data_collection_cron() { // 确保事件未已安排 if (!wp_next_scheduled('hourly_data_collection')) { // 安排每小时执行一次 wp_schedule_event(time(), 'hourly', 'hourly_data_collection'); } } add_action('wp', 'register_data_collection_cron'); // 定义采集函数 function perform_data_collection() { // 数据采集逻辑 $data_sources = get_option('data_collection_sources', array()); foreach ($data_sources as $source) { $collected_data = fetch_data_from_source($source); process_and_store_data($collected_data); } // 记录采集日志 update_option('last_collection_time', current_time('mysql')); } add_action('hourly_data_collection', 'perform_data_collection'); // 添加自定义时间间隔 function add_custom_cron_intervals($schedules) { $schedules['every_10_minutes'] = array( 'interval' => 600, 'display' => __('每10分钟') ); return $schedules; } add_filter('cron_schedules', 'add_custom_cron_intervals');
- RSS/Atom订阅采集: function fetch_rss_feed($feed_url) { include_once(ABSPATH . WPINC . '/feed.php'); // 获取RSS订阅 $rss = fetch_feed($feed_url); if (is_wp_error($rss)) { error_log('RSS采集错误: ' . $rss->get_error_message()); return false; } $max_items = $rss->get_item_quantity(10); // 获取最新10条 $rss_items = $rss->get_items(0, $max_items); $collected_data = array(); foreach ($rss_items as $item) { $data_entry = array( 'title' => $item->get_title(), 'content' => $item->get_content(), 'excerpt' => $item->get_description(), 'source_url' => $item->get_permalink(), 'publish_date' => $item->get_date('Y-m-d H:i:s'), 'author' => $item->get_author() ? $item->get_author()->get_name() : '', 'categories' => array() ); // 获取分类 $categories = $item->get_categories(); if ($categories) { foreach ($categories as $category) { $data_entry['categories'][] = $category->get_label(); } } $collected_data[] = $data_entry; } return $collected_data; } API数据采集: function fetch_api_data($api_url, $api_key = '') { $args = array( 'timeout' => 30, 'headers' => $api_key ? array('Authorization' => 'Bearer ' . $api_key) : array() ); $response = wp_remote_get($api_url, $args); if (is_wp_error($response)) { error_log('API请求错误: ' . $response->get_error_message()); return false; } $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); if (json_last_error() !== JSON_ERROR_NONE) { error_log('JSON解析错误: ' . json_last_error_msg()); return false; } return $data; } 网页内容抓取:对于网页抓取,建议使用WordPress内置的HTTP API配合DOM解析: function scrape_website_content($url, $selector) { // 获取网页内容 $response = wp_remote_get($url, array('timeout' => 30)); if (is_wp_error($response)) { return false; } $html = wp_remote_retrieve_body($response); // 使用DOMDocument解析HTML $dom = new DOMDocument(); @$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8')); $xpath = new DOMXPath($dom); $elements = $xpath->query($selector); $results = array(); foreach ($elements as $element) { $results[] = $dom->saveHTML($element); } return $results; } 注意:网页抓取应遵守robots.txt规则,尊重版权,并控制请求频率以避免对目标服务器造成负担。
- 采集到的数据需要有效存储和处理。WordPress提供了多种存储选项: 自定义数据库表:对于大量结构化数据,创建自定义数据库表可能更高效: function create_data_collection_table() { global $wpdb; $table_name = $wpdb->prefix . 'collected_data'; $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE IF NOT EXISTS $table_name ( id bigint(20) NOT NULL AUTO_INCREMENT, source_id varchar(100) NOT NULL, title text NOT NULL, content longtext, source_url varchar(500), collected_date datetime DEFAULT CURRENT_TIMESTAMP, processed tinyint(1) DEFAULT 0, PRIMARY KEY (id), KEY source_id (source_id), KEY processed (processed) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); } register_activation_hook(__FILE__, 'create_data_collection_table'); 使用自定义文章类型存储:对于大多数情况,使用自定义文章类型配合自定义字段是更简单的方法: function store_collected_data_as_post($data) { // 检查是否已存在相同内容(避免重复) $existing_post = get_posts(array( 'post_type' => 'collected_data', 'meta_query' => array( array( 'key' => 'source_url', 'value' => $data['source_url'] ) ), 'posts_per_page' => 1 )); if (!empty($existing_post)) { // 更新现有文章 $post_id = $existing_post[0]->ID; $post_data = array( 'ID' => $post_id, 'post_title' => $data['title'], 'post_content' => $data['content'], 'post_excerpt' => $data['excerpt'], 'post_status' => 'publish' ); wp_update_post($post_data); } else { // 创建新文章 $post_data = array( 'post_title' => $data['title'], 'post_content' => $data['content'], 'post_excerpt' => $data['excerpt'], 'post_status' => 'publish', 'post_type' => 'collected_data', 'post_date' => $data['publish_date'] ?: current_time('mysql') ); $post_id = wp_insert_post($post_data); } // 保存元数据 if ($post_id && !is_wp_error($post_id)) { update_post_meta($post_id, 'source_url', $data['source_url']); update_post_meta($post_id, 'original_author', $data['author']); update_post_meta($post_id, 'collected_date', current_time('mysql')); // 保存分类 if (!empty($data['categories'])) { $category_ids = array(); foreach ($data['categories'] as $category_name) { $term = term_exists($category_name, 'category'); if (!$term) { $term = wp_insert_term($category_name, 'category'); } if (!is_wp_error($term)) { $category_ids[] = (int)$term['term_id']; } } wp_set_post_terms($post_id, $category_ids, 'category'); } } return $post_id; }
- 采集的数据通常需要清洗和去重处理: function clean_and_deduplicate_data($data_array) { $unique_data = array(); $content_hashes = array(); foreach ($data_array as $data) { // 内容清洗 $data['title'] = sanitize_text_field($data['title']); $data['content'] = wp_kses_post($data['content']); // 过滤允许的HTML // 去除HTML标签获取纯文本用于去重 $content_text = wp_strip_all_tags($data['content']); $content_hash = md5($content_text); // 检查是否重复 if (!in_array($content_hash, $content_hashes)) { $content_hashes[] = $content_hash; $unique_data[] = $data; } } return $unique_data; }
-
- 信息聚合不仅仅是收集数据,更是将多源数据整合为有价值的信息流。常见的聚合策略包括: 时间线聚合:按时间顺序展示多源数据 主题聚合:按主题或分类组织相关内容 来源聚合:按数据源分类展示 混合聚合:结合多种维度展示数据
- 在WordPress主题中创建专门的聚合页面模板: <?php /* Template Name: 数据聚合页面 */ get_header(); // 获取聚合配置 $sources = get_field('aggregation_sources'); // 假设使用ACF字段 $layout = get_field('aggregation_layout', 'grid'); // 网格或列表布局 $items_per_page = get_field('items_per_page', 20); $current_page = max(1, get_query_var('paged')); ?> <div class="aggregation-container"> <header class="aggregation-header"> <h1><?php the_title(); ?></h1> <div class="aggregation-filters"> <select id="source-filter"> <option value="all">所有来源</option> <?php foreach ($sources as $source): ?> <option value="<?php echo esc_attr($source['value']); ?>"> <?php echo esc_html($source['label']); ?> </option> <?php endforeach; ?> </select> <select id="date-filter"> <option value="all">全部时间</option> <option value="today">今天</option> <option value="week">本周</option> <option value="month">本月</option> </select> </div> </header> <div class="aggregation-content" id="aggregation-results"> <?php // 查询聚合数据 $args = array( 'post_type' => 'collected_data', 'posts_per_page' => $items_per_page, 'paged' => $current_page, 'orderby' => 'date', 'order' => 'DESC' ); // 添加源过滤 if (isset($_GET['source']) && $_GET['source'] !== 'all') { $args['meta_query'] = array( array( 'key' => 'data_source', 'value' => sanitize_text_field($_GET['source']), 'compare' => '=' ) ); } // 添加日期过滤 if (isset($_GET['date_filter'])) { $date_filter = sanitize_text_field($_GET['date_filter']); $date_query = array(); switch ($date_filter) { case 'today': $date_query = array( 'after' => 'today midnight', 'inclusive' => true ); break; case 'week': $date_query = array( 'after' => '1 week ago' ); break; case 'month': $date_query = array( 'after' => '1 month ago' ); break; } if (!empty($date_query)) { $args['date_query'] = $date_query; } } $aggregation_query = new WP_Query($args); if ($aggregation_query->have_posts()): echo $layout === 'grid' ? '<div class="aggregation-grid">' : '<div class="aggregation-list">'; while ($aggregation_query->have_posts()): $aggregation_query->the_post(); include(locate_template('template-parts/aggregation-item.php')); endwhile; echo '</div>'; // 分页 echo '<div class="aggregation-pagination">'; echo paginate_links(array( 'total' => $aggregation_query->max_num_pages, 'current' => $current_page, 'prev_text' => '« 上一页', 'next_text' => '下一页 »' )); echo '</div>'; wp_reset_postdata(); else: echo '<p class="no-results">暂无聚合数据</p>'; endif; ?> </div> </div> <script> // AJAX过滤功能 jQuery(document).ready(function($) { $('#source-filter, #date-filter').on('change', function() { var source = $('#source-filter').val(); var dateFilter = $('#date-filter').val(); $.ajax({ url: '<?php echo admin_url("admin-ajax.php"); ?>', type: 'POST', data: { data', source: source, date_filter: dateFilter, page: 1 }, beforeSend: function() { $('#aggregation-results').html('<div class="loading">加载中...</div>'); }, success: function(response) { $('#aggregation-results').html(response); } }); }); });</script> <?phpget_footer(); #### 3.3 实时数据聚合与更新 对于需要实时展示的数据,可以结合AJAX和WebSocket技术: // 实时数据推送端点function realtime_aggregation_endpoint() { register_rest_route('aggregation/v1', '/realtime', array( 'methods' => 'GET', 'callback' => 'get_realtime_aggregation_data', 'permission_callback' => '__return_true' )); }add_action('rest_api_init', 'realtime_aggregation_endpoint'); function get_realtime_aggregation_data($request) { $last_id = $request->get_param('last_id'); $category = $request->get_param('category'); $args = array( 'post_type' => 'collected_data', 'posts_per_page' => 10, 'orderby' => 'date', 'order' => 'DESC' ); if ($last_id) { $args['date_query'] = array( 'after' => get_the_date('Y-m-d H:i:s', $last_id) ); } if ($category && $category !== 'all') { $args['tax_query'] = array( array( 'taxonomy' => 'category', 'field' => 'slug', 'terms' => $category ) ); } $query = new WP_Query($args); $data = array(); if ($query->have_posts()) { while ($query->have_posts()) { $query->the_post(); $data[] = array( 'id' => get_the_ID(), 'title' => get_the_title(), 'excerpt' => get_the_excerpt(), 'date' => get_the_date('Y-m-d H:i:s'), 'source' => get_post_meta(get_the_ID(), 'data_source', true), 'url' => get_permalink() ); } wp_reset_postdata(); } return rest_ensure_response(array( 'success' => true, 'data' => $data, 'timestamp' => current_time('timestamp') )); } 前端实时更新实现: // 前端实时数据监听class RealtimeAggregation { constructor(options) { this.options = Object.assign({ endpoint: '/wp-json/aggregation/v1/realtime', interval: 30000, // 30秒 container: '#realtime-feed', lastId: 0 }, options); this.init(); } init() { this.container = document.querySelector(this.options.container); if (!this.container) return; this.loadInitialData(); this.startPolling(); } async loadInitialData() { try { const response = await fetch(`${this.options.endpoint}?last_id=0`); const data = await response.json(); if (data.success && data.data.length > 0) { this.renderData(data.data); this.options.lastId = data.data[0].id; } } catch (error) { console.error('加载数据失败:', error); } } startPolling() { setInterval(() => { this.checkForUpdates(); }, this.options.interval); } async checkForUpdates() { try { const response = await fetch( `${this.options.endpoint}?last_id=${this.options.lastId}` ); const data = await response.json(); if (data.success && data.data.length > 0) { this.prependData(data.data); this.options.lastId = data.data[0].id; // 显示新数据通知 this.showNewItemsNotification(data.data.length); } } catch (error) { console.error('检查更新失败:', error); } } renderData(items) { items.forEach(item => { const itemElement = this.createItemElement(item); this.container.appendChild(itemElement); }); } prependData(items) { items.reverse().forEach(item => { const itemElement = this.createItemElement(item); this.container.insertBefore(itemElement, this.container.firstChild); }); } createItemElement(item) { const div = document.createElement('div'); div.className = 'realtime-item'; div.innerHTML = ` <div class="item-header"> <span class="source-badge">${this.escapeHtml(item.source)}</span> <span class="item-time">${this.formatTime(item.date)}</span> </div> <h3 class="item-title"> <a href="${this.escapeHtml(item.url)}">${this.escapeHtml(item.title)}</a> </h3> <p class="item-excerpt">${this.escapeHtml(item.excerpt)}</p> `; return div; } showNewItemsNotification(count) { // 实现新数据通知逻辑 const notification = document.createElement('div'); notification.className = 'new-items-notification'; notification.innerHTML = ` 有${count}条新内容,<a href="#" class="show-new">点击查看</a> `; notification.querySelector('.show-new').addEventListener('click', (e) => { e.preventDefault(); notification.remove(); }); document.body.appendChild(notification); setTimeout(() => { if (notification.parentNode) { notification.remove(); } }, 5000); } escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } formatTime(dateString) { const date = new Date(dateString); const now = new Date(); const diff = Math.floor((now - date) / 1000); // 秒 if (diff < 60) return '刚刚'; if (diff < 3600) return `${Math.floor(diff / 60)}分钟前`; if (diff < 86400) return `${Math.floor(diff / 3600)}小时前`; return date.toLocaleDateString(); } } // 初始化实时聚合document.addEventListener('DOMContentLoaded', () => { new RealtimeAggregation({ container: '#realtime-feed', interval: 15000 // 15秒 }); }); #### 3.4 智能推荐与个性化聚合 基于用户行为实现个性化内容推荐: class PersonalizedAggregation { private $user_id; private $preferences; public function __construct($user_id = null) { $this->user_id = $user_id ?: get_current_user_id(); $this->load_user_preferences(); } private function load_user_preferences() { if ($this->user_id) { $this->preferences = get_user_meta($this->user_id, 'aggregation_preferences', true); } if (empty($this->preferences)) { $this->preferences = array( 'preferred_categories' => array(), 'preferred_sources' => array(), 'reading_history' => array(), 'click_pattern' => array() ); } } public function track_user_interaction($post_id, $interaction_type = 'view') { if (!$this->user_id) return; $post_categories = wp_get_post_categories($post_id); $post_source = get_post_meta($post_id, 'data_source', true); // 更新阅读历史 $history = $this->preferences['reading_history']; array_unshift($history, array( 'post_id' => $post_id, 'timestamp' => current_time('timestamp'), 'type' => $interaction_type )); // 保持最近100条记录 $this->preferences['reading_history'] = array_slice($history, 0, 100); // 更新分类偏好 foreach ($post_categories as $cat_id) { if (!isset($this->preferences['preferred_categories'][$cat_id])) { $this->preferences['preferred_categories'][$cat_id] = 0; } $this->preferences['preferred_categories'][$cat_id] += 1; } // 更新来源偏好 if ($post_source) { if (!isset($this->preferences['preferred_sources'][$post_source])) { $this->preferences['preferred_sources'][$post_source] = 0; } $this->preferences['preferred_sources'][$post_source] += 1; } $this->save_preferences(); } public function get_personalized_feed($limit = 20) { $args = array( 'post_type' => 'collected_data', 'posts_per_page' => $limit, 'orderby' => 'relevance', 'meta_query' => array() ); // 基于用户偏好调整查询 if (!empty($this->preferences['preferred_categories'])) { arsort($this->preferences['preferred_categories']); $top_categories = array_slice( array_keys($this->preferences['preferred_categories']), 0, 3 ); $args['category__in'] = $top_categories; } if (!empty($this->preferences['preferred_sources'])) { arsort($this->preferences['preferred_sources']); $top_sources = array_slice( array_keys($this->preferences['preferred_sources']), 0, 2 ); $args['meta_query'][] = array( 'key' => 'data_source', 'value' => $top_sources, 'compare' => 'IN' ); } // 排除已读内容 if (!empty($this->preferences['reading_history'])) { $read_posts = array_column($this->preferences['reading_history'], 'post_id'); $args['post__not_in'] = array_unique($read_posts); } // 添加相关性评分 add_filter('posts_where', array($this, 'add_relevance_scoring')); $query = new WP_Query($args); remove_filter('posts_where', array($this, 'add_relevance_scoring')); return $query; } public function add_relevance_scoring($where) { // 基于用户偏好计算相关性得分的复杂逻辑 // 这里简化实现,实际应用中可能需要更复杂的算法 global $wpdb; if (!empty($this->preferences['preferred_categories'])) { // 为偏好的分类添加权重 $category_weights = array(); foreach ($this->preferences['preferred_categories'] as $cat_id => $count) { $weight = min(10, $count / 10); // 计算权重 $category_weights[$cat_id] = $weight; } // 这里可以添加更复杂的SQL逻辑来计算相关性 } return $where; } private function save_preferences() { if ($this->user_id) { update_user_meta( $this->user_id, 'aggregation_preferences', $this->preferences ); } } public function get_recommendations_based_on_similarity($post_id, $limit = 5) { $post_categories = wp_get_post_categories($post_id); $post_tags = wp_get_post_tags($post_id, array('fields' => 'ids')); $post_source = get_post_meta($post_id, 'data_source', true); $args = array( 'post_type' => 'collected_data', 'posts_per_page' => $limit, 'post__not_in' => array($post_id), 'orderby' => 'relevance' ); // 基于内容相似性查找相关文章 $tax_query = array('relation' => 'OR'); if (!empty($post_categories)) { $tax_query[] = array( 'taxonomy' => 'category', 'field' => 'term_id', 'terms' => $post_categories ); } if (!empty($post_tags)) { $tax_query[] = array( 'taxonomy' => 'post_tag', 'field' => 'term_id', 'terms' => $post_tags ); } if (!empty($tax_query)) { $args['tax_query'] = $tax_query; } if ($post_source) { $args['meta_query'] = array( array( 'key' => 'data_source', 'value' => $post_source, 'compare' => '=' ) ); } return new WP_Query($args); } } // 使用示例add_action('wp', function() { if (is_singular('collected_data')) { $personalizer = new PersonalizedAggregation(); $personalizer->track_user_interaction(get_the_ID()); } }); ### 第四部分:常用互联网小工具集成 #### 4.1 工具类插件架构设计 创建可扩展的小工具系统: // 小工具管理器类class ToolManager { private static $instance = null; private $tools = array(); private function __construct() { $this->load_tools(); add_action('init', array($this, 'register_tools')); } public static function get_instance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } private function load_tools() { // 加载内置工具 $this->register_tool('unit_converter', array( 'name' => '单位换算器', 'description' => '常用单位换算工具', 'callback' => array($this, 'render_unit_converter'), 'icon' => 'dashicons-calculator', 'category' => 'utility' )); $this->register_tool('color_picker', array( 'name' => '颜色选择器', 'description' => 'RGB/HEX颜色选择与转换', 'callback' => array($this, 'render_color_picker'), 'icon' => 'dashicons-art', 'category' => 'design' )); $this->register_tool('qrcode_generator', array( 'name' => '二维码生成器', 'description' => '生成自定义二维码', 'callback' => array($this, 'render_qrcode_generator'), 'icon' => 'dashicons-format-image', 'category' => 'generator' )); // 允许其他插件注册工具 do_action('tool_manager_register_tools', $this); } public function register_tool($slug, $args) { $defaults = array( 'name' => '', 'description' => '', 'callback' => null, 'icon' => 'dashicons-admin-tools', 'category' => 'general', 'settings' => array() ); $this->tools[$slug] = wp_parse_args($args, $defaults); } public function register_tools() { // 注册短代码 foreach ($this->tools as $slug => $tool) { add_shortcode('tool_' . $slug, $tool['callback']); } // 注册Gutenberg块 if (function_exists('register_block_type')) { $this->register_tool_blocks(); } } private function register_tool_blocks() { wp_register_script( 'tool-blocks', plugins_url('js/tool-blocks.js', __FILE__), array('wp-blocks', 'wp-element', 'wp-editor', 'wp-components'), '1.0.0', true ); register_block_type('tool-manager/tool', array( 'editor_script' => 'tool-blocks', 'render_callback' => array($this, 'render_tool_block') )); } public function render_tool_block($attributes) { $slug = $attributes['toolSlug'] ?? ''; if (isset($this->tools[$slug]) && is_callable($this->tools[$slug]['callback'])) { ob_start(); call_user_func($this->tools[$slug]['callback'], $attributes); return ob_get_clean(); } return '<p>工具未找到</p>'; } public function get_tools_by_category($category = '') { if (empty($category)) { return $this->tools; } return array_filter($this->tools, function($tool) use ($category) { return $tool['category'] === $category; }); } public function render_tool_selector() { $categories = array(); foreach ($this->tools as $tool) { if (!isset($categories[$tool['category']])) { $categories[$tool['category']] = array(); } $categories[$tool['category']][] = $tool; } ob_start(); ?> <div class="tool-selector"> <?php foreach ($categories as $category_name => $category_tools): ?> <div class="tool-category"> <h3><?php echo esc_html($this->get_category_label($category_name)); ?></h3> <div class="tool-grid"> <?php foreach ($category_tools as $slug => $tool): ?> <div class="tool-item" data-tool="<?php echo esc_attr($slug); ?>"> <div class="tool-icon"> <span class="dashicons <?php echo esc_attr($tool['icon']); ?>
在当今数字化时代,网站已不仅仅是信息展示的窗口,更是功能集成与服务的平台。WordPress作为全球最受欢迎的内容管理系统,占据了互联网上超过43%的网站份额。然而,许多用户仅将其视为简单的博客或内容发布工具,未能充分挖掘其作为强大开发平台的潜力。
实际上,通过代码二次开发,WordPress可以转型为功能丰富的应用平台,集成自动化数据采集、信息聚合以及各种实用小工具。本教程将深入探讨如何通过WordPress开发,实现网站自动化数据采集与信息聚合,并集成常用互联网小工具功能,帮助您将普通网站升级为智能化的多功能平台。
在开始WordPress二次开发之前,首先需要搭建合适的开发环境。推荐使用本地开发环境如XAMPP、MAMP或Local by Flywheel,这些工具提供了完整的PHP、MySQL和Web服务器环境。
对于代码编辑器,Visual Studio Code是目前最受欢迎的选择,配合以下扩展插件可极大提升开发效率:
- PHP Intelephense(PHP代码智能提示)
- WordPress Snippet(WordPress代码片段)
- GitLens(Git版本控制集成)
此外,建议安装调试工具如Query Monitor和Debug Bar,这些插件能帮助您在开发过程中实时监控数据库查询、PHP错误和性能数据。
要有效进行WordPress二次开发,必须深入理解其核心架构:
主题系统:WordPress主题控制网站的外观和显示方式。子主题开发是自定义功能而不影响父主题更新的最佳实践。创建子主题只需在wp-content/themes目录下建立新文件夹,包含style.css和functions.php文件。
插件系统:插件用于扩展WordPress功能,独立于主题。良好的插件应遵循单一职责原则,专注于特定功能的实现。
钩子机制:动作钩子(Action Hooks)和过滤器钩子(Filter Hooks)是WordPress扩展性的核心。动作钩子允许在特定点执行自定义代码,而过滤器钩子允许修改数据。
// 动作钩子示例
add_action('wp_head', 'custom_head_code');
function custom_head_code() {
echo '<meta name="custom-tag" content="value">';
}
// 过滤器钩子示例
add_filter('the_title', 'custom_title_format');
function custom_title_format($title) {
return '📌 ' . $title;
}
对于数据采集和聚合,自定义文章类型(CPT)和字段是基础。CPT允许您创建不同于标准文章和页面的内容类型,如“新闻”、“产品”或“数据条目”。
// 注册自定义文章类型
function register_data_collection_cpt() {
$labels = array(
'name' => '采集数据',
'singular_name' => '数据条目'
);
$args = array(
'labels' => $labels,
'public' => true,
'has_archive' => true,
'supports' => array('title', 'editor', 'custom-fields'),
'show_in_rest' => true, // 启用Gutenberg编辑器支持
);
register_post_type('collected_data', $args);
}
add_action('init', 'register_data_collection_cpt');
对于更复杂的字段需求,推荐使用Advanced Custom Fields(ACF)插件或Meta Box框架,它们提供了直观的字段管理界面。
在开发数据采集功能前,需要明确采集目标、数据源和更新频率。常见的数据源包括:
- RSS/Atom订阅源
- 公开API接口
- 网页抓取(需遵守robots.txt和法律法规)
- 社交媒体平台
- 公开数据库
设计数据采集系统时,应考虑以下因素:
- 数据源稳定性与可用性
- 采集频率与服务器负载平衡
- 数据去重与更新机制
- 错误处理与日志记录
- 版权与法律合规性
WordPress提供了内置的定时任务系统WP-Cron,可用于定期执行数据采集任务。但需要注意的是,WP-Cron基于页面访问触发,对于精确的定时任务可能不够可靠。对于高要求的采集任务,建议使用系统级的Cron任务。
// 注册定时采集任务
function register_data_collection_cron() {
// 确保事件未已安排
if (!wp_next_scheduled('hourly_data_collection')) {
// 安排每小时执行一次
wp_schedule_event(time(), 'hourly', 'hourly_data_collection');
}
}
add_action('wp', 'register_data_collection_cron');
// 定义采集函数
function perform_data_collection() {
// 数据采集逻辑
$data_sources = get_option('data_collection_sources', array());
foreach ($data_sources as $source) {
$collected_data = fetch_data_from_source($source);
process_and_store_data($collected_data);
}
// 记录采集日志
update_option('last_collection_time', current_time('mysql'));
}
add_action('hourly_data_collection', 'perform_data_collection');
// 添加自定义时间间隔
function add_custom_cron_intervals($schedules) {
$schedules['every_10_minutes'] = array(
'interval' => 600,
'display' => __('每10分钟')
);
return $schedules;
}
add_filter('cron_schedules', 'add_custom_cron_intervals');
RSS/Atom订阅采集:
function fetch_rss_feed($feed_url) {
include_once(ABSPATH . WPINC . '/feed.php');
// 获取RSS订阅
$rss = fetch_feed($feed_url);
if (is_wp_error($rss)) {
error_log('RSS采集错误: ' . $rss->get_error_message());
return false;
}
$max_items = $rss->get_item_quantity(10); // 获取最新10条
$rss_items = $rss->get_items(0, $max_items);
$collected_data = array();
foreach ($rss_items as $item) {
$data_entry = array(
'title' => $item->get_title(),
'content' => $item->get_content(),
'excerpt' => $item->get_description(),
'source_url' => $item->get_permalink(),
'publish_date' => $item->get_date('Y-m-d H:i:s'),
'author' => $item->get_author() ? $item->get_author()->get_name() : '',
'categories' => array()
);
// 获取分类
$categories = $item->get_categories();
if ($categories) {
foreach ($categories as $category) {
$data_entry['categories'][] = $category->get_label();
}
}
$collected_data[] = $data_entry;
}
return $collected_data;
}
API数据采集:
function fetch_api_data($api_url, $api_key = '') {
$args = array(
'timeout' => 30,
'headers' => $api_key ? array('Authorization' => 'Bearer ' . $api_key) : array()
);
$response = wp_remote_get($api_url, $args);
if (is_wp_error($response)) {
error_log('API请求错误: ' . $response->get_error_message());
return false;
}
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if (json_last_error() !== JSON_ERROR_NONE) {
error_log('JSON解析错误: ' . json_last_error_msg());
return false;
}
return $data;
}
网页内容抓取:
对于网页抓取,建议使用WordPress内置的HTTP API配合DOM解析:
function scrape_website_content($url, $selector) {
// 获取网页内容
$response = wp_remote_get($url, array('timeout' => 30));
if (is_wp_error($response)) {
return false;
}
$html = wp_remote_retrieve_body($response);
// 使用DOMDocument解析HTML
$dom = new DOMDocument();
@$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
$xpath = new DOMXPath($dom);
$elements = $xpath->query($selector);
$results = array();
foreach ($elements as $element) {
$results[] = $dom->saveHTML($element);
}
return $results;
}
注意:网页抓取应遵守robots.txt规则,尊重版权,并控制请求频率以避免对目标服务器造成负担。
采集到的数据需要有效存储和处理。WordPress提供了多种存储选项:
自定义数据库表:
对于大量结构化数据,创建自定义数据库表可能更高效:
function create_data_collection_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'collected_data';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id bigint(20) NOT NULL AUTO_INCREMENT,
source_id varchar(100) NOT NULL,
title text NOT NULL,
content longtext,
source_url varchar(500),
collected_date datetime DEFAULT CURRENT_TIMESTAMP,
processed tinyint(1) DEFAULT 0,
PRIMARY KEY (id),
KEY source_id (source_id),
KEY processed (processed)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
register_activation_hook(__FILE__, 'create_data_collection_table');
使用自定义文章类型存储:
对于大多数情况,使用自定义文章类型配合自定义字段是更简单的方法:
function store_collected_data_as_post($data) {
// 检查是否已存在相同内容(避免重复)
$existing_post = get_posts(array(
'post_type' => 'collected_data',
'meta_query' => array(
array(
'key' => 'source_url',
'value' => $data['source_url']
)
),
'posts_per_page' => 1
));
if (!empty($existing_post)) {
// 更新现有文章
$post_id = $existing_post[0]->ID;
$post_data = array(
'ID' => $post_id,
'post_title' => $data['title'],
'post_content' => $data['content'],
'post_excerpt' => $data['excerpt'],
'post_status' => 'publish'
);
wp_update_post($post_data);
} else {
// 创建新文章
$post_data = array(
'post_title' => $data['title'],
'post_content' => $data['content'],
'post_excerpt' => $data['excerpt'],
'post_status' => 'publish',
'post_type' => 'collected_data',
'post_date' => $data['publish_date'] ?: current_time('mysql')
);
$post_id = wp_insert_post($post_data);
}
// 保存元数据
if ($post_id && !is_wp_error($post_id)) {
update_post_meta($post_id, 'source_url', $data['source_url']);
update_post_meta($post_id, 'original_author', $data['author']);
update_post_meta($post_id, 'collected_date', current_time('mysql'));
// 保存分类
if (!empty($data['categories'])) {
$category_ids = array();
foreach ($data['categories'] as $category_name) {
$term = term_exists($category_name, 'category');
if (!$term) {
$term = wp_insert_term($category_name, 'category');
}
if (!is_wp_error($term)) {
$category_ids[] = (int)$term['term_id'];
}
}
wp_set_post_terms($post_id, $category_ids, 'category');
}
}
return $post_id;
}
采集的数据通常需要清洗和去重处理:
function clean_and_deduplicate_data($data_array) {
$unique_data = array();
$content_hashes = array();
foreach ($data_array as $data) {
// 内容清洗
$data['title'] = sanitize_text_field($data['title']);
$data['content'] = wp_kses_post($data['content']); // 过滤允许的HTML
// 去除HTML标签获取纯文本用于去重
$content_text = wp_strip_all_tags($data['content']);
$content_hash = md5($content_text);
// 检查是否重复
if (!in_array($content_hash, $content_hashes)) {
$content_hashes[] = $content_hash;
$unique_data[] = $data;
}
}
return $unique_data;
}
信息聚合不仅仅是收集数据,更是将多源数据整合为有价值的信息流。常见的聚合策略包括:
- 时间线聚合:按时间顺序展示多源数据
- 主题聚合:按主题或分类组织相关内容
- 来源聚合:按数据源分类展示
- 混合聚合:结合多种维度展示数据
在WordPress主题中创建专门的聚合页面模板:
<?php
/*
Template Name: 数据聚合页面
*/
get_header();
// 获取聚合配置
$sources = get_field('aggregation_sources'); // 假设使用ACF字段
$layout = get_field('aggregation_layout', 'grid'); // 网格或列表布局
$items_per_page = get_field('items_per_page', 20);
$current_page = max(1, get_query_var('paged'));
?>
<div class="aggregation-container">
<header class="aggregation-header">
<h1><?php the_title(); ?></h1>
<div class="aggregation-filters">
<select id="source-filter">
<option value="all">所有来源</option>
<?php foreach ($sources as $source): ?>
<option value="<?php echo esc_attr($source['value']); ?>">
<?php echo esc_html($source['label']); ?>
</option>
<?php endforeach; ?>
</select>
<select id="date-filter">
<option value="all">全部时间</option>
<option value="today">今天</option>
<option value="week">本周</option>
<option value="month">本月</option>
</select>
</div>
</header>
<div class="aggregation-content" id="aggregation-results">
<?php
// 查询聚合数据
$args = array(
'post_type' => 'collected_data',
'posts_per_page' => $items_per_page,
'paged' => $current_page,
'orderby' => 'date',
'order' => 'DESC'
);
// 添加源过滤
if (isset($_GET['source']) && $_GET['source'] !== 'all') {
$args['meta_query'] = array(
array(
'key' => 'data_source',
'value' => sanitize_text_field($_GET['source']),
'compare' => '='
)
);
}
// 添加日期过滤
if (isset($_GET['date_filter'])) {
$date_filter = sanitize_text_field($_GET['date_filter']);
$date_query = array();
switch ($date_filter) {
case 'today':
$date_query = array(
'after' => 'today midnight',
'inclusive' => true
);
break;
case 'week':
$date_query = array(
'after' => '1 week ago'
);
break;
case 'month':
$date_query = array(
'after' => '1 month ago'
);
break;
}
if (!empty($date_query)) {
$args['date_query'] = $date_query;
}
}
$aggregation_query = new WP_Query($args);
if ($aggregation_query->have_posts()):
echo $layout === 'grid' ? '<div class="aggregation-grid">' : '<div class="aggregation-list">';
while ($aggregation_query->have_posts()): $aggregation_query->the_post();
include(locate_template('template-parts/aggregation-item.php'));
endwhile;
echo '</div>';
// 分页
echo '<div class="aggregation-pagination">';
echo paginate_links(array(
'total' => $aggregation_query->max_num_pages,
'current' => $current_page,
'prev_text' => '« 上一页',
'next_text' => '下一页 »'
));
echo '</div>';
wp_reset_postdata();
else:
echo '<p class="no-results">暂无聚合数据</p>';
endif;
?>
</div>
</div>
<script>
// AJAX过滤功能
jQuery(document).ready(function($) {
$('#source-filter, #date-filter').on('change', function() {
var source = $('#source-filter').val();
var dateFilter = $('#date-filter').val();
$.ajax({
url: '<?php echo admin_url("admin-ajax.php"); ?>',
type: 'POST',
data: {
data',
source: source,
date_filter: dateFilter,
page: 1
},
beforeSend: function() {
$('#aggregation-results').html('<div class="loading">加载中...</div>');
},
success: function(response) {
$('#aggregation-results').html(response);
}
});
});
});
</script>
<?php
get_footer();
#### 3.3 实时数据聚合与更新
对于需要实时展示的数据,可以结合AJAX和WebSocket技术:
// 实时数据推送端点
function realtime_aggregation_endpoint() {
register_rest_route('aggregation/v1', '/realtime', array(
'methods' => 'GET',
'callback' => 'get_realtime_aggregation_data',
'permission_callback' => '__return_true'
));
}
add_action('rest_api_init', 'realtime_aggregation_endpoint');
function get_realtime_aggregation_data($request) {
$last_id = $request->get_param('last_id');
$category = $request->get_param('category');
$args = array(
'post_type' => 'collected_data',
'posts_per_page' => 10,
'orderby' => 'date',
'order' => 'DESC'
);
if ($last_id) {
$args['date_query'] = array(
'after' => get_the_date('Y-m-d H:i:s', $last_id)
);
}
if ($category && $category !== 'all') {
$args['tax_query'] = array(
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => $category
)
);
}
$query = new WP_Query($args);
$data = array();
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
$data[] = array(
'id' => get_the_ID(),
'title' => get_the_title(),
'excerpt' => get_the_excerpt(),
'date' => get_the_date('Y-m-d H:i:s'),
'source' => get_post_meta(get_the_ID(), 'data_source', true),
'url' => get_permalink()
);
}
wp_reset_postdata();
}
return rest_ensure_response(array(
'success' => true,
'data' => $data,
'timestamp' => current_time('timestamp')
));
}
前端实时更新实现:
// 前端实时数据监听
class RealtimeAggregation {
constructor(options) {
this.options = Object.assign({
endpoint: '/wp-json/aggregation/v1/realtime',
interval: 30000, // 30秒
container: '#realtime-feed',
lastId: 0
}, options);
this.init();
}
init() {
this.container = document.querySelector(this.options.container);
if (!this.container) return;
this.loadInitialData();
this.startPolling();
}
async loadInitialData() {
try {
const response = await fetch(`${this.options.endpoint}?last_id=0`);
const data = await response.json();
if (data.success && data.data.length > 0) {
this.renderData(data.data);
this.options.lastId = data.data[0].id;
}
} catch (error) {
console.error('加载数据失败:', error);
}
}
startPolling() {
setInterval(() => {
this.checkForUpdates();
}, this.options.interval);
}
async checkForUpdates() {
try {
const response = await fetch(
`${this.options.endpoint}?last_id=${this.options.lastId}`
);
const data = await response.json();
if (data.success && data.data.length > 0) {
this.prependData(data.data);
this.options.lastId = data.data[0].id;
// 显示新数据通知
this.showNewItemsNotification(data.data.length);
}
} catch (error) {
console.error('检查更新失败:', error);
}
}
renderData(items) {
items.forEach(item => {
const itemElement = this.createItemElement(item);
this.container.appendChild(itemElement);
});
}
prependData(items) {
items.reverse().forEach(item => {
const itemElement = this.createItemElement(item);
this.container.insertBefore(itemElement, this.container.firstChild);
});
}
createItemElement(item) {
const div = document.createElement('div');
div.className = 'realtime-item';
div.innerHTML = `
<div class="item-header">
<span class="source-badge">${this.escapeHtml(item.source)}</span>
<span class="item-time">${this.formatTime(item.date)}</span>
</div>
<h3 class="item-title">
<a href="${this.escapeHtml(item.url)}">${this.escapeHtml(item.title)}</a>
</h3>
<p class="item-excerpt">${this.escapeHtml(item.excerpt)}</p>
`;
return div;
}
showNewItemsNotification(count) {
// 实现新数据通知逻辑
const notification = document.createElement('div');
notification.className = 'new-items-notification';
notification.innerHTML = `
有${count}条新内容,<a href="#" class="show-new">点击查看</a>
`;
notification.querySelector('.show-new').addEventListener('click', (e) => {
e.preventDefault();
notification.remove();
});
document.body.appendChild(notification);
setTimeout(() => {
if (notification.parentNode) {
notification.remove();
}
}, 5000);
}
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
formatTime(dateString) {
const date = new Date(dateString);
const now = new Date();
const diff = Math.floor((now - date) / 1000); // 秒
if (diff < 60) return '刚刚';
if (diff < 3600) return `${Math.floor(diff / 60)}分钟前`;
if (diff < 86400) return `${Math.floor(diff / 3600)}小时前`;
return date.toLocaleDateString();
}
}
// 初始化实时聚合
document.addEventListener('DOMContentLoaded', () => {
new RealtimeAggregation({
container: '#realtime-feed',
interval: 15000 // 15秒
});
});
#### 3.4 智能推荐与个性化聚合
基于用户行为实现个性化内容推荐:
class PersonalizedAggregation {
private $user_id;
private $preferences;
public function __construct($user_id = null) {
$this->user_id = $user_id ?: get_current_user_id();
$this->load_user_preferences();
}
private function load_user_preferences() {
if ($this->user_id) {
$this->preferences = get_user_meta($this->user_id, 'aggregation_preferences', true);
}
if (empty($this->preferences)) {
$this->preferences = array(
'preferred_categories' => array(),
'preferred_sources' => array(),
'reading_history' => array(),
'click_pattern' => array()
);
}
}
public function track_user_interaction($post_id, $interaction_type = 'view') {
if (!$this->user_id) return;
$post_categories = wp_get_post_categories($post_id);
$post_source = get_post_meta($post_id, 'data_source', true);
// 更新阅读历史
$history = $this->preferences['reading_history'];
array_unshift($history, array(
'post_id' => $post_id,
'timestamp' => current_time('timestamp'),
'type' => $interaction_type
));
// 保持最近100条记录
$this->preferences['reading_history'] = array_slice($history, 0, 100);
// 更新分类偏好
foreach ($post_categories as $cat_id) {
if (!isset($this->preferences['preferred_categories'][$cat_id])) {
$this->preferences['preferred_categories'][$cat_id] = 0;
}
$this->preferences['preferred_categories'][$cat_id] += 1;
}
// 更新来源偏好
if ($post_source) {
if (!isset($this->preferences['preferred_sources'][$post_source])) {
$this->preferences['preferred_sources'][$post_source] = 0;
}
$this->preferences['preferred_sources'][$post_source] += 1;
}
$this->save_preferences();
}
public function get_personalized_feed($limit = 20) {
$args = array(
'post_type' => 'collected_data',
'posts_per_page' => $limit,
'orderby' => 'relevance',
'meta_query' => array()
);
// 基于用户偏好调整查询
if (!empty($this->preferences['preferred_categories'])) {
arsort($this->preferences['preferred_categories']);
$top_categories = array_slice(
array_keys($this->preferences['preferred_categories']),
0,
3
);
$args['category__in'] = $top_categories;
}
if (!empty($this->preferences['preferred_sources'])) {
arsort($this->preferences['preferred_sources']);
$top_sources = array_slice(
array_keys($this->preferences['preferred_sources']),
0,
2
);
$args['meta_query'][] = array(
'key' => 'data_source',
'value' => $top_sources,
'compare' => 'IN'
);
}
// 排除已读内容
if (!empty($this->preferences['reading_history'])) {
$read_posts = array_column($this->preferences['reading_history'], 'post_id');
$args['post__not_in'] = array_unique($read_posts);
}
// 添加相关性评分
add_filter('posts_where', array($this, 'add_relevance_scoring'));
$query = new WP_Query($args);
remove_filter('posts_where', array($this, 'add_relevance_scoring'));
return $query;
}
public function add_relevance_scoring($where) {
// 基于用户偏好计算相关性得分的复杂逻辑
// 这里简化实现,实际应用中可能需要更复杂的算法
global $wpdb;
if (!empty($this->preferences['preferred_categories'])) {
// 为偏好的分类添加权重
$category_weights = array();
foreach ($this->preferences['preferred_categories'] as $cat_id => $count) {
$weight = min(10, $count / 10); // 计算权重
$category_weights[$cat_id] = $weight;
}
// 这里可以添加更复杂的SQL逻辑来计算相关性
}
return $where;
}
private function save_preferences() {
if ($this->user_id) {
update_user_meta(
$this->user_id,
'aggregation_preferences',
$this->preferences
);
}
}
public function get_recommendations_based_on_similarity($post_id, $limit = 5) {
$post_categories = wp_get_post_categories($post_id);
$post_tags = wp_get_post_tags($post_id, array('fields' => 'ids'));
$post_source = get_post_meta($post_id, 'data_source', true);
$args = array(
'post_type' => 'collected_data',
'posts_per_page' => $limit,
'post__not_in' => array($post_id),
'orderby' => 'relevance'
);
// 基于内容相似性查找相关文章
$tax_query = array('relation' => 'OR');
if (!empty($post_categories)) {
$tax_query[] = array(
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => $post_categories
);
}
if (!empty($post_tags)) {
$tax_query[] = array(
'taxonomy' => 'post_tag',
'field' => 'term_id',
'terms' => $post_tags
);
}
if (!empty($tax_query)) {
$args['tax_query'] = $tax_query;
}
if ($post_source) {
$args['meta_query'] = array(
array(
'key' => 'data_source',
'value' => $post_source,
'compare' => '='
)
);
}
return new WP_Query($args);
}
}
// 使用示例
add_action('wp', function() {
if (is_singular('collected_data')) {
$personalizer = new PersonalizedAggregation();
$personalizer->track_user_interaction(get_the_ID());
}
});
### 第四部分:常用互联网小工具集成
#### 4.1 工具类插件架构设计
创建可扩展的小工具系统:
// 小工具管理器类
class ToolManager {
private static $instance = null;
private $tools = array();
private function __construct() {
$this->load_tools();
add_action('init', array($this, 'register_tools'));
}
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function load_tools() {
// 加载内置工具
$this->register_tool('unit_converter', array(
'name' => '单位换算器',
'description' => '常用单位换算工具',
'callback' => array($this, 'render_unit_converter'),
'icon' => 'dashicons-calculator',
'category' => 'utility'
));
$this->register_tool('color_picker', array(
'name' => '颜色选择器',
'description' => 'RGB/HEX颜色选择与转换',
'callback' => array($this, 'render_color_picker'),
'icon' => 'dashicons-art',
'category' => 'design'
));
$this->register_tool('qrcode_generator', array(
'name' => '二维码生成器',
'description' => '生成自定义二维码',
'callback' => array($this, 'render_qrcode_generator'),
'icon' => 'dashicons-format-image',
'category' => 'generator'
));
// 允许其他插件注册工具
do_action('tool_manager_register_tools', $this);
}
public function register_tool($slug, $args) {
$defaults = array(
'name' => '',
'description' => '',
'callback' => null,
'icon' => 'dashicons-admin-tools',
'category' => 'general',
'settings' => array()
);
$this->tools[$slug] = wp_parse_args($args, $defaults);
}
public function register_tools() {
// 注册短代码
foreach ($this->tools as $slug => $tool) {
add_shortcode('tool_' . $slug, $tool['callback']);
}
// 注册Gutenberg块
if (function_exists('register_block_type')) {
$this->register_tool_blocks();
}
}
private function register_tool_blocks() {
wp_register_script(
'tool-blocks',
plugins_url('js/tool-blocks.js', __FILE__),
array('wp-blocks', 'wp-element', 'wp-editor', 'wp-components'),
'1.0.0',
true
);
register_block_type('tool-manager/tool', array(
'editor_script' => 'tool-blocks',
'render_callback' => array($this, 'render_tool_block')
));
}
public function render_tool_block($attributes) {
$slug = $attributes['toolSlug'] ?? '';
if (isset($this->tools[$slug]) && is_callable($this->tools[$slug]['callback'])) {
ob_start();
call_user_func($this->tools[$slug]['callback'], $attributes);
return ob_get_clean();
}
return '<p>工具未找到</p>';
}
public function get_tools_by_category($category = '') {
if (empty($category)) {
return $this->tools;
}
return array_filter($this->tools, function($tool) use ($category) {
return $tool['category'] === $category;
});
}
public function render_tool_selector() {
$categories = array();
foreach ($this->tools as $tool) {
if (!isset($categories[$tool['category']])) {
$categories[$tool['category']] = array();
}
$categories[$tool['category']][] = $tool;
}
ob_start();
?>
<div class="tool-selector">
<?php foreach ($categories as $category_name => $category_tools): ?>
<div class="tool-category">
<h3><?php echo esc_html($this->get_category_label($category_name)); ?></h3>
<div class="tool-grid">
<?php foreach ($category_tools as $slug => $tool): ?>
<div class="tool-item" data-tool="<?php echo esc_attr($slug); ?>">
<div class="tool-icon">
<span class="dashicons <?php echo esc_attr($tool['icon']); ?>


