文章目录[隐藏]
WordPress网络传媒柔性内容多渠道同步插件开发教程
一、插件开发背景与需求分析
在当今数字化媒体时代,网络传媒机构需要在多个平台同步发布内容,包括微信公众号、微博、头条号、知乎等多个渠道。手动同步不仅效率低下,还容易出错。本教程将指导您开发一个WordPress柔性内容多渠道同步插件,实现一键发布到多个平台。
核心需求:
- 支持自定义内容转换规则,适应不同平台的内容格式要求
- 可配置的发布渠道管理
- 定时发布和即时发布两种模式
- 发布状态跟踪和错误处理
- 支持图片等媒体资源的自动处理
二、插件基础结构搭建
首先,我们需要创建插件的基本文件结构:
<?php
/**
* Plugin Name: 柔性内容多渠道同步插件
* Plugin URI: https://yourwebsite.com/
* Description: 实现WordPress内容一键同步到多个媒体平台
* Version: 1.0.0
* Author: 您的名称
* License: GPL v2 or later
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('FLEX_SYNC_VERSION', '1.0.0');
define('FLEX_SYNC_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('FLEX_SYNC_PLUGIN_URL', plugin_dir_url(__FILE__));
// 初始化插件
class FlexContentSync {
private static $instance = null;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$this->init_hooks();
}
private function init_hooks() {
// 激活/停用插件时的操作
register_activation_hook(__FILE__, array($this, 'activate'));
register_deactivation_hook(__FILE__, array($this, 'deactivate'));
// 初始化
add_action('plugins_loaded', array($this, 'init'));
// 添加管理菜单
add_action('admin_menu', array($this, 'add_admin_menu'));
// 保存文章时触发同步
add_action('save_post', array($this, 'on_save_post'), 10, 3);
}
public function activate() {
// 创建必要的数据库表
$this->create_tables();
// 设置默认选项
$this->set_default_options();
}
public function deactivate() {
// 清理临时数据
// 注意:这里不清除配置数据,以便重新激活时保留设置
}
public function init() {
// 加载文本域
load_plugin_textdomain('flex-sync', false, dirname(plugin_basename(__FILE__)) . '/languages');
// 加载必要的类
$this->load_dependencies();
}
// 其他方法将在后续章节实现
}
// 启动插件
FlexContentSync::get_instance();
?>
三、数据库设计与渠道管理
我们需要设计数据库表来存储渠道配置和同步记录:
<?php
// 在FlexContentSync类中添加以下方法
private function create_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_name_channels = $wpdb->prefix . 'flex_sync_channels';
$table_name_logs = $wpdb->prefix . 'flex_sync_logs';
// 渠道配置表
$sql_channels = "CREATE TABLE IF NOT EXISTS $table_name_channels (
id mediumint(9) NOT NULL AUTO_INCREMENT,
channel_name varchar(100) NOT NULL,
channel_type varchar(50) NOT NULL,
api_config text NOT NULL,
is_active tinyint(1) DEFAULT 1,
content_rules text,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) $charset_collate;";
// 同步日志表
$sql_logs = "CREATE TABLE IF NOT EXISTS $table_name_logs (
id mediumint(9) NOT NULL AUTO_INCREMENT,
post_id bigint(20) NOT NULL,
channel_id mediumint(9) NOT NULL,
status varchar(20) NOT NULL,
response text,
published_url varchar(500),
published_at datetime,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY post_id (post_id),
KEY channel_id (channel_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql_channels);
dbDelta($sql_logs);
}
// 渠道管理类
class ChannelManager {
public static function get_channels($active_only = true) {
global $wpdb;
$table_name = $wpdb->prefix . 'flex_sync_channels';
$where = $active_only ? "WHERE is_active = 1" : "";
$query = "SELECT * FROM $table_name $where ORDER BY channel_name";
return $wpdb->get_results($query);
}
public static function add_channel($data) {
global $wpdb;
$table_name = $wpdb->prefix . 'flex_sync_channels';
$defaults = array(
'is_active' => 1,
'content_rules' => json_encode(array(
'max_length' => 0,
'image_count' => 0,
'format' => 'html'
))
);
$data = wp_parse_args($data, $defaults);
return $wpdb->insert($table_name, $data);
}
public static function update_channel($id, $data) {
global $wpdb;
$table_name = $wpdb->prefix . 'flex_sync_channels';
return $wpdb->update($table_name, $data, array('id' => $id));
}
public static function delete_channel($id) {
global $wpdb;
$table_name = $wpdb->prefix . 'flex_sync_channels';
return $wpdb->delete($table_name, array('id' => $id));
}
}
?>
四、内容转换引擎开发
不同平台对内容格式有不同的要求,我们需要开发一个灵活的内容转换引擎:
<?php
class ContentTransformer {
private $post;
private $channel_rules;
public function __construct($post_id, $channel_rules) {
$this->post = get_post($post_id);
$this->channel_rules = is_string($channel_rules) ?
json_decode($channel_rules, true) : $channel_rules;
}
/**
* 转换内容为适合目标平台的格式
*/
public function transform() {
$content = $this->post->post_content;
// 应用转换规则
$content = $this->apply_rules($content);
// 处理图片
$content = $this->process_images($content);
// 处理长度限制
$content = $this->handle_length_limit($content);
return array(
'title' => $this->transform_title(),
'content' => $content,
'excerpt' => $this->transform_excerpt(),
'images' => $this->extract_images()
);
}
private function apply_rules($content) {
$rules = $this->channel_rules;
// 移除短代码
if (isset($rules['remove_shortcodes']) && $rules['remove_shortcodes']) {
$content = strip_shortcodes($content);
}
// 转换HTML标签
if (isset($rules['format']) && $rules['format'] === 'plaintext') {
$content = wp_strip_all_tags($content);
} elseif (isset($rules['format']) && $rules['format'] === 'markdown') {
$content = $this->html_to_markdown($content);
}
// 添加来源声明
if (isset($rules['add_source']) && $rules['add_source']) {
$content .= "nn来源: " . get_bloginfo('name');
}
return $content;
}
private function process_images($content) {
// 提取内容中的图片
preg_match_all('/<img[^>]+>/i', $content, $img_matches);
foreach ($img_matches[0] as $img_tag) {
// 根据渠道规则处理图片
// 这里可以添加图片上传到图床、压缩等逻辑
if (isset($this->channel_rules['upload_images']) &&
$this->channel_rules['upload_images']) {
// 上传图片到指定图床
$new_img_tag = $this->upload_and_replace_image($img_tag);
$content = str_replace($img_tag, $new_img_tag, $content);
}
}
return $content;
}
private function handle_length_limit($content) {
if (isset($this->channel_rules['max_length']) &&
$this->channel_rules['max_length'] > 0) {
$max_length = intval($this->channel_rules['max_length']);
if (mb_strlen($content) > $max_length) {
$content = mb_substr($content, 0, $max_length - 3) . '...';
}
}
return $content;
}
private function transform_title() {
$title = $this->post->post_title;
// 这里可以添加标题转换规则
if (isset($this->channel_rules['title_prefix'])) {
$title = $this->channel_rules['title_prefix'] . $title;
}
return $title;
}
private function extract_images() {
$images = array();
$content = $this->post->post_content;
preg_match_all('/<img[^>]+src="([^">]+)"/i', $content, $matches);
if (!empty($matches[1])) {
$images = $matches[1];
// 限制图片数量
if (isset($this->channel_rules['image_count']) &&
$this->channel_rules['image_count'] > 0) {
$max_images = intval($this->channel_rules['image_count']);
$images = array_slice($images, 0, $max_images);
}
}
return $images;
}
// 其他辅助方法...
}
?>
五、平台API集成与发布器
接下来,我们实现不同平台的API集成:
<?php
// 发布器基类
abstract class PlatformPublisher {
protected $api_config;
protected $channel_id;
public function __construct($api_config, $channel_id) {
$this->api_config = $api_config;
$this->channel_id = $channel_id;
}
abstract public function publish($transformed_content);
abstract public function test_connection();
protected function log_result($post_id, $status, $response, $published_url = '') {
global $wpdb;
$table_name = $wpdb->prefix . 'flex_sync_logs';
$data = array(
'post_id' => $post_id,
'channel_id' => $this->channel_id,
'status' => $status,
'response' => is_array($response) ? json_encode($response) : $response,
'published_url' => $published_url,
'published_at' => current_time('mysql')
);
return $wpdb->insert($table_name, $data);
}
}
// 微信公众号发布器
class WeChatPublisher extends PlatformPublisher {
public function publish($transformed_content) {
// 微信公众号API实现
$api_url = 'https://api.weixin.qq.com/cgi-bin/material/add_news';
$data = array(
'articles' => array(
array(
'title' => $transformed_content['title'],
'content' => $transformed_content['content'],
'digest' => $transformed_content['excerpt'],
'thumb_media_id' => $this->upload_cover_image($transformed_content['images'])
)
)
);
// 获取访问令牌
$access_token = $this->get_access_token();
// 发送请求
$response = wp_remote_post($api_url . '?access_token=' . $access_token, array(
'body' => json_encode($data, JSON_UNESCAPED_UNICODE),
'headers' => array('Content-Type' => 'application/json')
));
if (is_wp_error($response)) {
$this->log_result(
$transformed_content['post_id'],
'error',
$response->get_error_message()
);
return false;
}
$body = json_decode(wp_remote_retrieve_body($response), true);
if (isset($body['media_id'])) {
$this->log_result(
$transformed_content['post_id'],
'success',
$body,
'https://mp.weixin.qq.com/s/' . $body['media_id']
);
return true;
} else {
$this->log_result(
$transformed_content['post_id'],
'error',
$body
);
return false;
}
}
private function get_access_token() {
// 实现获取access_token的逻辑
// 这里应该包含缓存机制,避免频繁请求
return 'your_access_token';
}
private function upload_cover_image($images) {
// 上传封面图片到微信服务器
if (!empty($images)) {
// 实现图片上传逻辑
return 'thumb_media_id';
}
return '';
}
public function test_connection() {
// 测试API连接
return array('success' => true, 'message' => '连接成功');
}
}
// 发布器工厂
class PublisherFactory {
public static function create($channel_type, $api_config, $channel_id) {
switch ($channel_type) {
case 'wechat':
return new WeChatPublisher($api_config, $channel_id);
case 'weibo':
// 返回微博发布器实例
// return new WeiboPublisher($api_config, $channel_id);
case 'zhihu':
// 返回知乎发布器实例
// return new ZhihuPublisher($api_config, $channel_id);
default:
throw new Exception('不支持的渠道类型: ' . $channel_type);
}
}
}
?>
六、管理界面与配置页面
最后,我们创建插件的管理界面:
<?php
// 在FlexContentSync类中添加管理菜单方法
public function add_admin_menu() {
// 主菜单
add_menu_page(
'多渠道同步',
'内容同步',
'manage_options',
'flex-sync',
array($this, 'render_main_page'),
'dashicons-share',
30
);
// 子菜单
add_submenu_page(
'flex-sync',
'渠道管理',
'渠道管理',
'manage_options',
'flex-sync-channels',
array($this, 'render_channels_page')
);
add_submenu_page(
'flex-sync',
'同步日志',
'同步日志',
'manage_options',
'flex-sync-logs',
array($this, 'render_logs_page')
);
add_submenu_page(
'flex-sync',
'设置',
'设置',
'manage_options',
'flex-sync-settings',
array($this, 'render_settings_page')
);
}
public function render_main_page() {
?>
<div class="wrap">
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
<div class="card">
<h2>快速发布</h2>
<form method="post" action="">
<?php wp_nonce_field('flex_sync_quick_publish', 'flex_sync_nonce'); ?>
<table class="form-table">
<tr>
<th scope="row">选择文章</th>
<td>
<select name="post_id" required>
<option value="">选择要发布的文章</option>
<?php
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => 50
);
$posts = get_posts($args);
foreach ($posts as $post) {
echo '<option value="' . $post->ID . '">' .
esc_html($post->post_title) . '</option>';
}
?>
</select>
</td>
</tr>
<tr>
<th scope="row">选择渠道</th>
<td>
<?php
$channels = ChannelManager::get_channels();
foreach ($channels as $channel) {
echo '<label>';
echo '<input type="checkbox" name="channels[]" value="' .
$channel->id . '"> ';
echo esc_html($channel->channel_name);
echo '</label><br>';
}
?>
</td>
</tr>
</table>
<p class="submit">
<input type="submit" name="submit" class="button button-primary"
value="立即发布">
<input type="submit" name="schedule" class="button"
value="定时发布">
</p>
</form>
</div>
<div class="card">
<h2>发布统计</h2>
<p>最近7天发布情况统计图将显示在这里</p>
<!-- 这里可以添加统计图表 -->
</div>
</div>
<?php
}
// 处理发布请求
public function handle_publish_request() {
publish', 'flex_sync_nonce')) {
$post_id = intval($_POST['post_id']);
$channels = isset($_POST['channels']) ? array_map('intval', $_POST['channels']) : array();
if ($post_id && !empty($channels)) {
$this->sync_to_channels($post_id, $channels);
// 显示成功消息
add_settings_error(
'flex_sync_messages',
'flex_sync_message',
'内容已开始同步到选定的渠道',
'success'
);
}
}
}
?>
## 七、文章编辑界面集成
为了让用户在编辑文章时就能同步,我们在文章编辑页面添加元框:
<?php
class PostMetaBox {
public static function init() {
add_action('add_meta_boxes', array(__CLASS__, 'add_meta_box'));
add_action('save_post', array(__CLASS__, 'save_meta_box'), 10, 2);
add_action('admin_enqueue_scripts', array(__CLASS__, 'enqueue_scripts'));
}
public static function add_meta_box() {
add_meta_box(
'flex_sync_meta_box',
'多渠道同步',
array(__CLASS__, 'render_meta_box'),
'post',
'side',
'high'
);
}
public static function render_meta_box($post) {
wp_nonce_field('flex_sync_meta_box', 'flex_sync_meta_box_nonce');
// 获取已配置的渠道
$channels = ChannelManager::get_channels();
// 获取该文章已同步的渠道
$synced_channels = self::get_synced_channels($post->ID);
?>
<div id="flex-sync-meta-box">
<p><strong>选择要同步的渠道:</strong></p>
<?php if (empty($channels)): ?>
<p class="description">请先在<a href="<?php echo admin_url('admin.php?page=flex-sync-channels'); ?>">渠道管理</a>中添加渠道。</p>
<?php else: ?>
<div class="channel-list">
<?php foreach ($channels as $channel): ?>
<label>
<input type="checkbox"
name="flex_sync_channels[]"
value="<?php echo esc_attr($channel->id); ?>"
<?php checked(in_array($channel->id, $synced_channels)); ?>>
<?php echo esc_html($channel->channel_name); ?>
<?php if (in_array($channel->id, $synced_channels)): ?>
<span class="dashicons dashicons-yes" style="color: #46b450;"></span>
<?php endif; ?>
</label><br>
<?php endforeach; ?>
</div>
<div style="margin-top: 15px;">
<label>
<input type="checkbox" name="flex_sync_immediate" value="1">
发布时立即同步
</label>
</div>
<div style="margin-top: 10px;">
<button type="button" id="flex-sync-test" class="button button-secondary">
测试所选渠道
</button>
<button type="button" id="flex-sync-preview" class="button button-secondary">
内容预览
</button>
</div>
<div id="flex-sync-status" style="margin-top: 10px; display: none;">
<!-- 同步状态将在这里显示 -->
</div>
<?php endif; ?>
</div>
<script type="text/javascript">
jQuery(document).ready(function($) {
$('#flex-sync-test').on('click', function() {
var channels = [];
$('input[name="flex_sync_channels[]"]:checked').each(function() {
channels.push($(this).val());
});
if (channels.length === 0) {
alert('请至少选择一个渠道');
return;
}
$('#flex-sync-status').html('<p>测试中...</p>').show();
$.post(ajaxurl, {
action: 'flex_sync_test_channels',
post_id: <?php echo $post->ID; ?>,
channels: channels,
nonce: '<?php echo wp_create_nonce("flex_sync_test"); ?>'
}, function(response) {
$('#flex-sync-status').html(response.data);
});
});
$('#flex-sync-preview').on('click', function() {
var channels = [];
$('input[name="flex_sync_channels[]"]:checked').each(function() {
channels.push($(this).val());
});
if (channels.length === 0) {
alert('请至少选择一个渠道');
return;
}
// 打开预览窗口
window.open('<?php echo admin_url("admin-ajax.php?action=flex_sync_preview&post_id=" . $post->ID); ?>&channels=' + channels.join(','),
'preview', 'width=800,height=600');
});
});
</script>
<?php
}
public static function save_meta_box($post_id, $post) {
// 验证nonce
if (!isset($_POST['flex_sync_meta_box_nonce']) ||
!wp_verify_nonce($_POST['flex_sync_meta_box_nonce'], 'flex_sync_meta_box')) {
return;
}
// 检查自动保存
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
// 检查权限
if (!current_user_can('edit_post', $post_id)) {
return;
}
// 保存选择的渠道
if (isset($_POST['flex_sync_channels'])) {
$channels = array_map('intval', $_POST['flex_sync_channels']);
update_post_meta($post_id, '_flex_sync_channels', $channels);
} else {
delete_post_meta($post_id, '_flex_sync_channels');
}
// 如果勾选了立即同步,并且文章已发布
if (isset($_POST['flex_sync_immediate']) && $post->post_status === 'publish') {
$channels = isset($_POST['flex_sync_channels']) ?
array_map('intval', $_POST['flex_sync_channels']) : array();
if (!empty($channels)) {
// 异步执行同步,避免阻塞保存过程
wp_schedule_single_event(time() + 5, 'flex_sync_async_publish', array($post_id, $channels));
}
}
}
public static function get_synced_channels($post_id) {
global $wpdb;
$table_name = $wpdb->prefix . 'flex_sync_logs';
$query = $wpdb->prepare(
"SELECT DISTINCT channel_id FROM $table_name WHERE post_id = %d AND status = 'success'",
$post_id
);
$results = $wpdb->get_col($query);
return $results ? array_map('intval', $results) : array();
}
public static function enqueue_scripts($hook) {
if ('post.php' === $hook || 'post-new.php' === $hook) {
wp_enqueue_script(
'flex-sync-admin',
FLEX_SYNC_PLUGIN_URL . 'assets/js/admin.js',
array('jquery'),
FLEX_SYNC_VERSION,
true
);
wp_localize_script('flex-sync-admin', 'flexSync', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('flex_sync_ajax')
));
}
}
}
// 初始化元框
PostMetaBox::init();
?>
## 八、AJAX处理与异步任务
处理前端AJAX请求和后台异步任务:
<?php
class AjaxHandler {
public static function init() {
// 测试渠道连接
add_action('wp_ajax_flex_sync_test_channels', array(__CLASS__, 'test_channels'));
// 内容预览
add_action('wp_ajax_flex_sync_preview', array(__CLASS__, 'preview_content'));
// 手动触发同步
add_action('wp_ajax_flex_sync_manual', array(__CLASS__, 'manual_sync'));
// 获取同步状态
add_action('wp_ajax_flex_sync_status', array(__CLASS__, 'get_sync_status'));
// 异步发布任务
add_action('flex_sync_async_publish', array(__CLASS__, 'async_publish'), 10, 2);
}
public static function test_channels() {
check_ajax_referer('flex_sync_test', 'nonce');
$post_id = intval($_POST['post_id']);
$channel_ids = isset($_POST['channels']) ? array_map('intval', $_POST['channels']) : array();
if (empty($channel_ids)) {
wp_send_json_error('请选择要测试的渠道');
}
$results = array();
foreach ($channel_ids as $channel_id) {
$channel = self::get_channel_by_id($channel_id);
if ($channel) {
try {
$publisher = PublisherFactory::create(
$channel->channel_type,
json_decode($channel->api_config, true),
$channel_id
);
$test_result = $publisher->test_connection();
$results[] = array(
'channel' => $channel->channel_name,
'success' => $test_result['success'],
'message' => $test_result['message']
);
} catch (Exception $e) {
$results[] = array(
'channel' => $channel->channel_name,
'success' => false,
'message' => $e->getMessage()
);
}
}
}
ob_start();
?>
<div class="test-results">
<h4>渠道连接测试结果:</h4>
<ul>
<?php foreach ($results as $result): ?>
<li>
<strong><?php echo esc_html($result['channel']); ?>:</strong>
<?php if ($result['success']): ?>
<span style="color: green;">✓ <?php echo esc_html($result['message']); ?></span>
<?php else: ?>
<span style="color: red;">✗ <?php echo esc_html($result['message']); ?></span>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php
$html = ob_get_clean();
wp_send_json_success($html);
}
public static function preview_content() {
$post_id = intval($_GET['post_id']);
$channel_ids = isset($_GET['channels']) ?
array_map('intval', explode(',', $_GET['channels'])) : array();
?>
<!DOCTYPE html>
<html>
<head>
<title>内容预览</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.preview-container { max-width: 800px; margin: 0 auto; }
.channel-preview { margin-bottom: 40px; border: 1px solid #ddd; padding: 20px; }
.channel-name { background: #f1f1f1; padding: 10px; margin: -20px -20px 20px -20px; }
.content-preview { line-height: 1.6; }
.image-preview { max-width: 100%; height: auto; margin: 10px 0; }
</style>
</head>
<body>
<div class="preview-container">
<h1>内容预览</h1>
<?php foreach ($channel_ids as $channel_id):
$channel = self::get_channel_by_id($channel_id);
if (!$channel) continue;
$transformer = new ContentTransformer($post_id, $channel->content_rules);
$transformed = $transformer->transform();
?>
<div class="channel-preview">
<div class="channel-name">
<h2><?php echo esc_html($channel->channel_name); ?></h2>
</div>
<div class="content-preview">
<h3><?php echo esc_html($transformed['title']); ?></h3>
<div><?php echo wpautop($transformed['content']); ?></div>
<?php if (!empty($transformed['images'])): ?>
<h4>包含的图片:</h4>
<?php foreach ($transformed['images'] as $image): ?>
<img src="<?php echo esc_url($image); ?>" class="image-preview">
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
</body>
</html>
<?php
exit;
}
public static function async_publish($post_id, $channels) {
// 这里调用同步方法
$flex_sync = FlexContentSync::get_instance();
$flex_sync->sync_to_channels($post_id, $channels);
}
private static function get_channel_by_id($channel_id) {
global $wpdb;
$table_name = $wpdb->prefix . 'flex_sync_channels';
return $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $table_name WHERE id = %d",
$channel_id
));
}
}
// 初始化AJAX处理器
AjaxHandler::init();
?>
## 九、定时任务与批量处理
实现定时同步和批量处理功能:
<?php
class BatchProcessor {
public static function init() {
// 注册定时任务
add_filter('cron_schedules', array(__CLASS__, 'add_cron_schedules'));
add_action('flex_sync_batch_process', array(__CLASS__, 'process_batch'));
// 激活插件时安排定时任务
register_activation_hook(__FILE__, array(__CLASS__, 'schedule_cron'));
register_deactivation_hook(__FILE__, array(__CLASS__, 'unschedule_cron'));
}
public static function add_cron_schedules($schedules) {
$schedules['flex_sync_5min'] = array(
'interval' => 300,
'display' => __('每5分钟', 'flex-sync')
);
$schedules['flex_sync_hourly'] = array(
'interval' => 3600,
'display' => __('每小时', 'flex-sync')
);
return $schedules;
}
public static function schedule_cron() {
if (!wp_next_scheduled('flex_sync_batch_process')) {
wp_schedule_event(time(), 'flex_sync_hourly', 'flex_sync_batch_process');
}
}
public static function unschedule_cron() {
$timestamp = wp_next_scheduled('flex_sync_batch_process');
if ($timestamp) {
wp_unschedule_event($timestamp, 'flex_sync_batch_process');
}
}
public static function process_batch() {
// 获取需要定时发布的文章
$pending_posts = self::get_pending_posts();
foreach ($pending_posts as $post) {
// 获取该文章需要同步的渠道
$channels = get_post_meta($post->ID, '_flex_sync_scheduled', true);
if ($channels && is_array($channels)) {
$flex_sync = FlexContentSync::get_instance();
$flex_sync->sync_to_channels($post->ID, $channels);
// 清除定时标记
delete_post_meta($post->ID, '_flex_sync_scheduled');
}
}
// 清理旧的同步日志(保留30天)
self::cleanup_old_logs();
}
private static function get_pending_posts() {
global $wpdb;
$query = "
SELECT p.ID, p.post_title
FROM {$wpdb->posts} p
INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
WHERE p.post_status = 'publish'
AND pm.meta_key = '_flex_sync_scheduled'
AND pm.meta_value != ''
ORDER BY p.post_date DESC
LIMIT 20
";
return $wpdb->get_results($query);
}
private static function cleanup_old_logs() {
global $wpdb;
$table_name = $wpdb->prefix . 'flex_sync_logs';
$thirty_days_ago = date('Y-m-d H:i:s', strtotime('-30 days'));
$wpdb->query($wpdb->prepare(
"DELETE FROM $table_name WHERE created_at < %s",
$thirty_days_ago
));
}
/**
* 批量同步多篇文章到多个渠道
*/
public static function batch_sync($post_ids, $channel_ids) {
$results = array();
foreach ($post_ids as $post_id) {
foreach ($channel_ids as $channel_id) {
try {
$flex_sync = FlexContentSync::get_instance();
$success = $flex_sync->sync_to_channel($post_id, $channel_id);
$results[] = array(
'post_id' => $post_id,
'channel_id' => $channel_id,
'success' => $success,
'message' => $success ? '同步成功' : '同步失败'
);
} catch (Exception $e) {
$results[] = array(
'post_id' => $post_id,
'channel_id' => $channel_id,
'success' => false,
'message' => $e->getMessage()
);
}
}
}
return $results;
}
}
