文章目录[隐藏]
WordPress开发教程:集成网站自动化数据采集与信息聚合工具,通过WordPress程序的代码二次开发实现常用互联网小工具功能
引言:WordPress的无限可能
在当今数字化时代,网站已不仅仅是信息展示的窗口,更是功能集成与服务的平台。WordPress作为全球最受欢迎的内容管理系统,占据了互联网上超过43%的网站份额。然而,许多用户仅将其视为简单的博客或内容发布工具,未能充分挖掘其作为强大开发平台的潜力。
实际上,通过代码二次开发,WordPress可以转型为功能丰富的应用平台,集成自动化数据采集、信息聚合以及各种实用小工具。本教程将深入探讨如何通过WordPress开发,实现网站自动化数据采集与信息聚合,并集成常用互联网小工具功能,帮助您将普通网站升级为智能化的多功能平台。
第一部分:WordPress开发环境搭建与基础知识
1.1 开发环境配置
在开始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错误和性能数据。
1.2 WordPress主题与插件架构理解
要有效进行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;
}
1.3 自定义文章类型与字段
对于数据采集和聚合,自定义文章类型(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框架,它们提供了直观的字段管理界面。
第二部分:自动化数据采集系统开发
2.1 数据采集策略与规划
在开发数据采集功能前,需要明确采集目标、数据源和更新频率。常见的数据源包括:
- RSS/Atom订阅源
- 公开API接口
- 网页抓取(需遵守robots.txt和法律法规)
- 社交媒体平台
- 公开数据库
设计数据采集系统时,应考虑以下因素:
- 数据源稳定性与可用性
- 采集频率与服务器负载平衡
- 数据去重与更新机制
- 错误处理与日志记录
- 版权与法律合规性
2.2 WordPress定时任务系统
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');
2.3 数据采集方法实现
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规则,尊重版权,并控制请求频率以避免对目标服务器造成负担。
2.4 数据存储与处理
采集到的数据需要有效存储和处理。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;
}
2.5 数据清洗与去重
采集的数据通常需要清洗和去重处理:
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;
}
第三部分:信息聚合与展示系统
3.1 数据聚合策略
信息聚合不仅仅是收集数据,更是将多源数据整合为有价值的信息流。常见的聚合策略包括:
- 时间线聚合:按时间顺序展示多源数据
- 主题聚合:按主题或分类组织相关内容
- 来源聚合:按数据源分类展示
- 混合聚合:结合多种维度展示数据
3.2 创建聚合页面模板
在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']); ?>
