文章目录[隐藏]
网络传媒WordPress多站点柔性内容同步管理插件开发教程
一、项目背景与需求分析
在当今网络传媒行业中,内容分发效率直接决定了信息传播的广度和深度。许多传媒机构使用WordPress多站点(Multisite)架构来管理多个子站点,但面临着一个共同挑战:如何在多个站点之间高效、灵活地同步和管理内容?
传统的内容同步方法存在诸多局限:
- 手动复制粘贴效率低下且容易出错
- 硬编码的同步规则缺乏灵活性
- 无法根据不同内容类型和站点特性进行差异化同步
- 缺乏版本控制和冲突解决机制
本教程将指导您开发一个"柔性内容同步管理插件",该插件能够:
- 根据预设规则自动同步指定内容
- 支持多种同步模式(实时、定时、手动)
- 允许自定义内容转换规则
- 提供冲突检测和解决机制
- 具备完整的日志和错误处理系统
二、插件架构设计
2.1 核心模块划分
<?php
/**
* 柔性内容同步管理插件 - 主文件
* Plugin Name: 柔性内容同步管理器
* Plugin URI: https://yourdomain.com/
* Description: WordPress多站点内容同步管理解决方案
* Version: 1.0.0
* Author: 网络传媒技术团队
* License: GPL v2 or later
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('FCSM_VERSION', '1.0.0');
define('FCSM_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('FCSM_PLUGIN_URL', plugin_dir_url(__FILE__));
// 主控制器类
class Flexible_Content_Sync_Manager {
private static $instance = null;
private $sync_rules = array();
private $scheduler;
private $logger;
// 单例模式
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$this->load_dependencies();
$this->init_hooks();
}
// 加载依赖模块
private function load_dependencies() {
require_once FCSM_PLUGIN_DIR . 'includes/class-sync-scheduler.php';
require_once FCSM_PLUGIN_DIR . 'includes/class-content-processor.php';
require_once FCSM_PLUGIN_DIR . 'includes/class-conflict-resolver.php';
require_once FCSM_PLUGIN_DIR . 'includes/class-logger.php';
require_once FCSM_PLUGIN_DIR . 'includes/class-rule-manager.php';
$this->scheduler = new FCSM_Sync_Scheduler();
$this->logger = new FCSM_Logger();
}
// 初始化WordPress钩子
private function init_hooks() {
add_action('init', array($this, 'init'));
add_action('admin_menu', array($this, 'add_admin_menu'));
add_action('save_post', array($this, 'handle_post_save'), 10, 3);
}
// 初始化方法
public function init() {
// 加载同步规则
$this->load_sync_rules();
}
// 加载同步规则
private function load_sync_rules() {
$rule_manager = new FCSM_Rule_Manager();
$this->sync_rules = $rule_manager->get_active_rules();
}
}
?>
2.2 数据库设计
<?php
/**
* 数据库表创建与维护
*/
class FCSM_Database {
// 创建插件所需的数据表
public static function create_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
// 同步规则表
$table_rules = $wpdb->prefix . 'fcsm_sync_rules';
$sql_rules = "CREATE TABLE IF NOT EXISTS $table_rules (
id mediumint(9) NOT NULL AUTO_INCREMENT,
rule_name varchar(255) NOT NULL,
source_site_id bigint(20) NOT NULL,
target_site_ids text NOT NULL,
post_types text NOT NULL,
sync_conditions text NOT NULL,
sync_mode varchar(50) DEFAULT 'manual',
sync_schedule varchar(50) DEFAULT '',
status tinyint(1) DEFAULT 1,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) $charset_collate;";
// 同步日志表
$table_logs = $wpdb->prefix . 'fcsm_sync_logs';
$sql_logs = "CREATE TABLE IF NOT EXISTS $table_logs (
id bigint(20) NOT NULL AUTO_INCREMENT,
rule_id mediumint(9) NOT NULL,
source_post_id bigint(20) NOT NULL,
target_post_id bigint(20) DEFAULT NULL,
target_site_id bigint(20) NOT NULL,
sync_status varchar(50) NOT NULL,
sync_message text,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY rule_id (rule_id),
KEY source_post_id (source_post_id)
) $charset_collate;";
// 冲突记录表
$table_conflicts = $wpdb->prefix . 'fcsm_conflicts';
$sql_conflicts = "CREATE TABLE IF NOT EXISTS $table_conflicts (
id bigint(20) NOT NULL AUTO_INCREMENT,
post_id bigint(20) NOT NULL,
site_id bigint(20) NOT NULL,
conflict_type varchar(100) NOT NULL,
conflict_data text NOT NULL,
resolution varchar(50) DEFAULT 'pending',
resolved_by bigint(20) DEFAULT NULL,
resolved_at datetime DEFAULT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql_rules);
dbDelta($sql_logs);
dbDelta($sql_conflicts);
}
}
?>
三、核心功能实现
3.1 内容处理器开发
<?php
/**
* 内容处理器 - 负责内容的转换和同步
*/
class FCSM_Content_Processor {
/**
* 同步单篇文章到目标站点
*
* @param int $post_id 源文章ID
* @param int $target_site_id 目标站点ID
* @param array $rule 同步规则
* @return array 同步结果
*/
public function sync_post_to_site($post_id, $target_site_id, $rule) {
// 切换到源站点获取文章数据
switch_to_blog($rule['source_site_id']);
$source_post = get_post($post_id, ARRAY_A);
if (!$source_post) {
restore_current_blog();
return array(
'success' => false,
'message' => '源文章不存在'
);
}
// 获取文章元数据
$post_meta = get_post_meta($post_id);
// 获取分类和标签
$categories = wp_get_post_categories($post_id, array('fields' => 'ids'));
$tags = wp_get_post_tags($post_id, array('fields' => 'ids'));
// 获取特色图片
$thumbnail_id = get_post_thumbnail_id($post_id);
restore_current_blog();
// 切换到目标站点
switch_to_blog($target_site_id);
// 检查文章是否已存在
$existing_post_id = $this->find_existing_post($source_post, $target_site_id);
// 准备文章数据
$post_data = $this->prepare_post_data($source_post, $rule);
if ($existing_post_id) {
// 更新现有文章
$post_data['ID'] = $existing_post_id;
$new_post_id = wp_update_post($post_data, true);
$action = 'updated';
} else {
// 创建新文章
$new_post_id = wp_insert_post($post_data, true);
$action = 'created';
}
if (is_wp_error($new_post_id)) {
restore_current_blog();
return array(
'success' => false,
'message' => $new_post_id->get_error_message()
);
}
// 同步元数据
$this->sync_post_meta($new_post_id, $post_meta, $rule);
// 同步分类和标签
$this->sync_taxonomies($new_post_id, $categories, $tags, $rule);
// 同步特色图片
if ($thumbnail_id) {
$this->sync_featured_image($new_post_id, $thumbnail_id, $rule);
}
restore_current_blog();
return array(
'success' => true,
'post_id' => $new_post_id,
'action' => $action,
'message' => '文章同步成功'
);
}
/**
* 准备文章数据
*/
private function prepare_post_data($source_post, $rule) {
// 基础字段映射
$post_data = array(
'post_title' => $source_post['post_title'],
'post_content' => $source_post['post_content'],
'post_excerpt' => $source_post['post_excerpt'],
'post_status' => $this->map_post_status($source_post['post_status'], $rule),
'post_type' => $source_post['post_type'],
'post_author' => $this->map_author($source_post['post_author'], $rule),
'post_date' => $source_post['post_date'],
'post_date_gmt' => $source_post['post_date_gmt']
);
// 应用内容转换规则
if (!empty($rule['content_transform'])) {
$post_data = $this->apply_content_transform($post_data, $rule['content_transform']);
}
return $post_data;
}
/**
* 同步文章元数据
*/
private function sync_post_meta($post_id, $source_meta, $rule) {
$meta_blacklist = array('_edit_lock', '_edit_last');
$meta_whitelist = isset($rule['meta_whitelist']) ? $rule['meta_whitelist'] : array();
foreach ($source_meta as $meta_key => $meta_values) {
// 跳过黑名单中的元数据
if (in_array($meta_key, $meta_blacklist)) {
continue;
}
// 如果设置了白名单,只同步白名单中的元数据
if (!empty($meta_whitelist) && !in_array($meta_key, $meta_whitelist)) {
continue;
}
// 删除旧的元数据
delete_post_meta($post_id, $meta_key);
// 添加新的元数据
foreach ($meta_values as $meta_value) {
// 处理序列化数据
$meta_value = maybe_unserialize($meta_value);
add_post_meta($post_id, $meta_key, $meta_value);
}
}
}
}
?>
3.2 冲突解决器实现
<?php
/**
* 冲突解决器 - 处理内容同步中的冲突
*/
class FCSM_Conflict_Resolver {
/**
* 检测并处理冲突
*/
public function detect_and_resolve_conflicts($source_post_id, $target_site_id, $rule) {
$conflicts = array();
// 检测标题冲突
$title_conflict = $this->detect_title_conflict($source_post_id, $target_site_id);
if ($title_conflict) {
$conflicts[] = $title_conflict;
}
// 检测内容冲突
$content_conflict = $this->detect_content_conflict($source_post_id, $target_site_id);
if ($content_conflict) {
$conflicts[] = $content_conflict;
}
// 根据规则自动解决冲突
if (!empty($conflicts) && isset($rule['auto_resolve_conflicts'])) {
foreach ($conflicts as $conflict) {
$this->auto_resolve_conflict($conflict, $rule);
}
}
return $conflicts;
}
/**
* 检测标题冲突
*/
private function detect_title_conflict($source_post_id, $target_site_id) {
global $wpdb;
switch_to_blog($target_site_id);
$source_title = get_the_title($source_post_id);
// 查找是否有相同标题的文章
$query = $wpdb->prepare(
"SELECT ID, post_title FROM {$wpdb->posts}
WHERE post_title = %s AND post_type = 'post'
AND post_status IN ('publish', 'draft', 'pending')",
$source_title
);
$existing_posts = $wpdb->get_results($query);
restore_current_blog();
if (!empty($existing_posts)) {
return array(
'type' => 'title_duplicate',
'source_post_id' => $source_post_id,
'target_site_id' => $target_site_id,
'conflicting_posts' => $existing_posts,
'message' => '存在标题相同的文章'
);
}
return false;
}
/**
* 自动解决冲突
*/
private function auto_resolve_conflict($conflict, $rule) {
switch ($conflict['type']) {
case 'title_duplicate':
$this->resolve_title_conflict($conflict, $rule);
break;
case 'content_duplicate':
$this->resolve_content_conflict($conflict, $rule);
break;
}
}
/**
* 解决标题冲突
*/
private function resolve_title_conflict($conflict, $rule) {
$resolution_strategy = isset($rule['conflict_resolution']['title'])
? $rule['conflict_resolution']['title']
: 'rename';
switch ($resolution_strategy) {
case 'rename':
// 在标题后添加时间戳
$new_title = get_the_title($conflict['source_post_id']) . ' - ' . current_time('Y-m-d H:i:s');
wp_update_post(array(
'ID' => $conflict['source_post_id'],
'post_title' => $new_title
));
break;
case 'skip':
// 跳过同步
return false;
case 'overwrite':
// 覆盖现有文章(需要额外处理)
break;
}
return true;
}
}
?>
四、管理界面开发
4.1 规则管理界面
<?php
/**
* 规则管理界面
*/
class FCSM_Admin_Interface {
/**
* 添加管理菜单
*/
public function add_admin_menu() {
add_menu_page(
'柔性内容同步管理',
'内容同步',
'manage_options',
'fcsm-dashboard',
array($this, 'render_dashboard'),
'dashicons-update',
30
);
add_submenu_page(
'fcsm-dashboard',
'同步规则',
'同步规则',
'manage_options',
'fcsm-rules',
array($this, 'render_rules_page')
);
add_submenu_page(
'fcsm-dashboard',
'同步日志',
'同步日志',
'manage_options',
'fcsm-logs',
array($this, 'render_logs_page')
);
add_submenu_page(
'fcsm-dashboard',
'冲突管理',
'冲突管理',
'manage_options',
'fcsm-conflicts',
array($this, 'render_conflicts_page')
);
}
/**
* 渲染规则管理页面
*/
public function render_rules_page() {
?>
<div class="wrap">
<h1 class="wp-heading-inline">同步规则管理</h1>
<a href="<?php echo admin_url('admin.php?page=fcsm-rules&action=add'); ?>" class="page-title-action">
添加新规则
</a>
<hr class="wp-header-end">
<div id="fcsm-rules-container">
<?php
$rules_table = new FCSM_Rules_Table();
$rules_table->prepare_items();
$rules_table->display();
?>
</div>
<!-- 规则编辑表单 -->
<div id="fcsm-rule-form" style="display: none;">
<form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
<input type="hidden" name="action" value="fcsm_save_rule">
<?php wp_nonce_field('fcsm_save_rule_nonce'); ?>
<table class="form-table">
<tr>
<th scope="row"><label for="rule_name">规则名称</label></th>
<td><input type="text" id="rule_name" name="rule_name" class="regular-text" required></td>
</tr>
<tr>
<th scope="row"><label for="source_site">源站点</label></th>
<td>
<select id="source_site" name="source_site_id" required>
<option value="">选择源站点</option>
<?php
$sites = get_sites();
foreach ($sites as $site) {
echo '<option value="' . $site->blog_id . '">' . get_blog_details($site->blog_id)->blogname . '</option>';
}
?>
</select>
</td>
</tr>
<tr>
4.2 规则配置界面(续)
<tr>
<th scope="row"><label for="target_sites">目标站点</label></th>
<td>
<select id="target_sites" name="target_site_ids[]" multiple="multiple" class="fcsm-select2" style="width: 100%;" required>
<?php
$sites = get_sites();
foreach ($sites as $site) {
echo '<option value="' . $site->blog_id . '">' . get_blog_details($site->blog_id)->blogname . '</option>';
}
?>
</select>
<p class="description">按住Ctrl键可多选</p>
</td>
</tr>
<tr>
<th scope="row"><label for="post_types">内容类型</label></th>
<td>
<select id="post_types" name="post_types[]" multiple="multiple" class="fcsm-select2" style="width: 100%;" required>
<?php
$post_types = get_post_types(array('public' => true), 'objects');
foreach ($post_types as $post_type) {
echo '<option value="' . $post_type->name . '">' . $post_type->label . '</option>';
}
?>
</select>
</td>
</tr>
<tr>
<th scope="row"><label for="sync_mode">同步模式</label></th>
<td>
<select id="sync_mode" name="sync_mode" onchange="toggleScheduleField()">
<option value="manual">手动同步</option>
<option value="auto">自动同步</option>
<option value="scheduled">定时同步</option>
</select>
</td>
</tr>
<tr id="schedule_field" style="display: none;">
<th scope="row"><label for="sync_schedule">同步计划</label></th>
<td>
<select id="sync_schedule" name="sync_schedule">
<option value="hourly">每小时</option>
<option value="twicedaily">每12小时</option>
<option value="daily">每天</option>
<option value="weekly">每周</option>
<option value="custom">自定义</option>
</select>
<div id="custom_schedule" style="display: none; margin-top: 10px;">
<input type="text" name="custom_cron_expression" placeholder="Cron表达式,如: 0 2 * * *" class="regular-text">
<p class="description">使用标准的Cron表达式格式</p>
</div>
</td>
</tr>
<tr>
<th scope="row"><label for="sync_conditions">同步条件</label></th>
<td>
<textarea id="sync_conditions" name="sync_conditions" rows="5" cols="50" placeholder='例如: {"post_status": "publish", "categories": [1,2]}'></textarea>
<p class="description">JSON格式的条件表达式</p>
</td>
</tr>
<tr>
<th scope="row"><label for="content_transform">内容转换规则</label></th>
<td>
<textarea id="content_transform" name="content_transform" rows="5" cols="50" placeholder='例如: {"replace": [["旧关键词", "新关键词"]], "append": "版权声明"}'></textarea>
<p class="description">JSON格式的转换规则</p>
</td>
</tr>
<tr>
<th scope="row"><label>冲突解决策略</label></th>
<td>
<fieldset>
<legend class="screen-reader-text">冲突解决策略</legend>
<label>
<input type="radio" name="conflict_resolution[title]" value="rename" checked>
重命名标题
</label><br>
<label>
<input type="radio" name="conflict_resolution[title]" value="skip">
跳过同步
</label><br>
<label>
<input type="radio" name="conflict_resolution[title]" value="overwrite">
覆盖内容
</label>
</fieldset>
</td>
</tr>
<tr>
<th scope="row"><label for="meta_whitelist">元数据白名单</label></th>
<td>
<input type="text" id="meta_whitelist" name="meta_whitelist" class="large-text" placeholder="_thumbnail_id, _custom_field1, _custom_field2">
<p class="description">逗号分隔的元数据键名,留空则同步所有元数据</p>
</td>
</tr>
</table>
<p class="submit">
<input type="submit" name="submit" id="submit" class="button button-primary" value="保存规则">
<a href="<?php echo admin_url('admin.php?page=fcsm-rules'); ?>" class="button">取消</a>
</p>
</form>
</div>
<script>
jQuery(document).ready(function($) {
// 初始化Select2
$('.fcsm-select2').select2();
// 显示/隐藏计划字段
window.toggleScheduleField = function() {
var mode = $('#sync_mode').val();
if (mode === 'scheduled') {
$('#schedule_field').show();
} else {
$('#schedule_field').hide();
}
}
// 显示/隐藏自定义计划字段
$('#sync_schedule').change(function() {
if ($(this).val() === 'custom') {
$('#custom_schedule').show();
} else {
$('#custom_schedule').hide();
}
});
// 表单验证
$('form').submit(function(e) {
var ruleName = $('#rule_name').val();
if (!ruleName.trim()) {
alert('请输入规则名称');
e.preventDefault();
return false;
}
// 验证JSON格式
try {
var conditions = $('#sync_conditions').val();
if (conditions.trim()) {
JSON.parse(conditions);
}
var transform = $('#content_transform').val();
if (transform.trim()) {
JSON.parse(transform);
}
} catch (err) {
alert('JSON格式错误: ' + err.message);
e.preventDefault();
return false;
}
});
});
</script>
<?php
}
/**
* 渲染日志页面
*/
public function render_logs_page() {
?>
<div class="wrap">
<h1>同步日志</h1>
<div class="fcsm-filters">
<form method="get">
<input type="hidden" name="page" value="fcsm-logs">
<label for="filter_rule">规则:</label>
<select name="rule_id" id="filter_rule">
<option value="">所有规则</option>
<?php
global $wpdb;
$rules = $wpdb->get_results("SELECT id, rule_name FROM {$wpdb->prefix}fcsm_sync_rules");
foreach ($rules as $rule) {
$selected = isset($_GET['rule_id']) && $_GET['rule_id'] == $rule->id ? 'selected' : '';
echo '<option value="' . $rule->id . '" ' . $selected . '>' . $rule->rule_name . '</option>';
}
?>
</select>
<label for="filter_status">状态:</label>
<select name="status" id="filter_status">
<option value="">所有状态</option>
<option value="success" <?php echo isset($_GET['status']) && $_GET['status'] == 'success' ? 'selected' : ''; ?>>成功</option>
<option value="failed" <?php echo isset($_GET['status']) && $_GET['status'] == 'failed' ? 'selected' : ''; ?>>失败</option>
<option value="partial" <?php echo isset($_GET['status']) && $_GET['status'] == 'partial' ? 'selected' : ''; ?>>部分成功</option>
</select>
<label for="filter_date">日期:</label>
<input type="date" name="date" id="filter_date" value="<?php echo isset($_GET['date']) ? $_GET['date'] : ''; ?>">
<input type="submit" class="button" value="筛选">
<a href="<?php echo admin_url('admin.php?page=fcsm-logs'); ?>" class="button">重置</a>
</form>
</div>
<?php
$logs_table = new FCSM_Logs_Table();
$logs_table->prepare_items();
$logs_table->display();
?>
<div class="fcsm-log-actions">
<form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
<input type="hidden" name="action" value="fcsm_export_logs">
<?php wp_nonce_field('fcsm_export_logs_nonce'); ?>
<input type="submit" class="button" value="导出日志">
</form>
<form method="post" action="<?php echo admin_url('admin-post.php'); ?>" onsubmit="return confirm('确定要清空所有日志吗?此操作不可恢复。');">
<input type="hidden" name="action" value="fcsm_clear_logs">
<?php wp_nonce_field('fcsm_clear_logs_nonce'); ?>
<input type="submit" class="button button-secondary" value="清空日志">
</form>
</div>
</div>
<?php
}
}
?>
五、高级功能实现
5.1 智能内容转换引擎
<?php
/**
* 智能内容转换引擎
*/
class FCSM_Content_Transformer {
/**
* 应用内容转换规则
*/
public function transform_content($content, $transform_rules) {
if (empty($transform_rules) || !is_array($transform_rules)) {
return $content;
}
// 文本替换
if (isset($transform_rules['replace']) && is_array($transform_rules['replace'])) {
foreach ($transform_rules['replace'] as $replacement) {
if (is_array($replacement) && count($replacement) >= 2) {
$content = str_replace($replacement[0], $replacement[1], $content);
}
}
}
// 正则表达式替换
if (isset($transform_rules['regex_replace']) && is_array($transform_rules['regex_replace'])) {
foreach ($transform_rules['regex_replace'] as $pattern => $replacement) {
$content = preg_replace($pattern, $replacement, $content);
}
}
// 添加前缀/后缀
if (isset($transform_rules['prepend'])) {
$content = $transform_rules['prepend'] . $content;
}
if (isset($transform_rules['append'])) {
$content .= $transform_rules['append'];
}
// 图片URL重写
if (isset($transform_rules['rewrite_image_urls'])) {
$content = $this->rewrite_image_urls($content, $transform_rules['rewrite_image_urls']);
}
// 自定义转换函数
if (isset($transform_rules['custom_callback']) && is_callable($transform_rules['custom_callback'])) {
$content = call_user_func($transform_rules['custom_callback'], $content);
}
return $content;
}
/**
* 重写图片URL
*/
private function rewrite_image_urls($content, $config) {
$source_domain = isset($config['source_domain']) ? $config['source_domain'] : '';
$target_domain = isset($config['target_domain']) ? $config['target_domain'] : '';
if (empty($source_domain) || empty($target_domain)) {
return $content;
}
// 匹配图片标签
$pattern = '/<img[^>]+src="([^"]*' . preg_quote($source_domain, '/') . '[^"]*)"[^>]*>/i';
$content = preg_replace_callback($pattern, function($matches) use ($source_domain, $target_domain) {
$new_src = str_replace($source_domain, $target_domain, $matches[1]);
return str_replace($matches[1], $new_src, $matches[0]);
}, $content);
// 匹配背景图片
$pattern = '/background(-image)?:s*url(["']?([^"')]*' . preg_quote($source_domain, '/') . '[^"')]*)["']?)/i';
$content = preg_replace_callback($pattern, function($matches) use ($source_domain, $target_domain) {
$new_url = str_replace($source_domain, $target_domain, $matches[2]);
return str_replace($matches[2], $new_url, $matches[0]);
}, $content);
return $content;
}
/**
* 智能分类映射
*/
public function map_categories($source_categories, $mapping_rules) {
$mapped_categories = array();
if (empty($mapping_rules) || !is_array($mapping_rules)) {
return $source_categories;
}
foreach ($source_categories as $source_cat_id) {
// 直接映射
if (isset($mapping_rules['direct'][$source_cat_id])) {
$mapped_categories[] = $mapping_rules['direct'][$source_cat_id];
continue;
}
// 名称匹配映射
$source_cat = get_category($source_cat_id);
if ($source_cat && isset($mapping_rules['by_name'][$source_cat->name])) {
$mapped_categories[] = $mapping_rules['by_name'][$source_cat->name];
continue;
}
// 默认映射
if (isset($mapping_rules['default'])) {
$mapped_categories[] = $mapping_rules['default'];
}
}
return array_unique($mapped_categories);
}
}
?>
5.2 批量同步处理器
<?php
/**
* 批量同步处理器
*/
class FCSM_Batch_Sync_Processor {
private $batch_size = 10;
private $max_retries = 3;
/**
* 执行批量同步
*/
public function process_batch_sync($rule_id, $post_ids = array()) {
$rule = $this->get_rule($rule_id);
if (!$rule) {
return array(
'success' => false,
'message' => '规则不存在'
);
}
// 如果没有指定文章ID,根据规则获取文章
if (empty($post_ids)) {
$post_ids = $this->get_posts_by_rule($rule);
}
// 分批处理
$batches = array_chunk($post_ids, $this->batch_size);
$results = array(
'total' => count($post_ids),
'success' => 0,
'failed' => 0,
'details' => array()
);
foreach ($batches as $batch_index => $batch) {
$batch_result = $this->process_single_batch($batch, $rule);
$results['success'] += $batch_result['success'];
$results['failed'] += $batch_result['failed'];
$results['details'][] = $batch_result;
// 记录进度
$this->update_batch_progress($rule_id, $batch_index + 1, count($batches));
// 防止超时,每批处理完后休息一下
if (count($batches) > 1 && $batch_index < count($batches) - 1) {
sleep(1);
}
}
return $results;
}
/**
* 处理单批文章
*/
private function process_single_batch($post_ids, $rule) {
$batch_result = array(
'success' => 0,
'failed' => 0,
'posts' => array()
);
$content_processor = new FCSM_Content_Processor();
$conflict_resolver = new FCSM_Conflict_Resolver();
foreach ($post_ids as $post_id) {
$post_result = array(
'post_id' => $post_id,
'sync_results' => array()
);
// 处理每个目标站点
foreach ($rule['target_site_ids'] as $target_site_id) {
// 检测冲突
$conflicts = $conflict_resolver->detect_and_resolve_conflicts(
$post_id,
$target_site_id,
$rule
);
// 执行同步
$sync_result = $content_processor->sync_post_to_site(
$post_id,
$target_site_id,
$rule
);
// 记录结果
$post_result['sync_results'][$target_site_id] = array(
'success' => $sync_result['success'],
'message' => $sync_result['message'],
'conflicts' => $conflicts,
'new_post_id' => isset($sync_result['post_id']) ? $sync_result['post_id'] : null
);
if ($sync_result['success']) {
$batch_result['success']++;
} else {
$batch_result['failed']++;
}
// 记录日志
$this->log_sync_result($rule['id'], $post_id, $target_site_id, $sync_result);
}
$batch_result['posts'][] = $post_result;
}
return $batch_result;
}
/**
* 根据规则获取文章
*/
