网络传媒柔性内容分发的WordPress插件开发教程
引言:柔性内容分发的重要性
在当今网络传媒环境中,内容分发不再局限于简单的"一对多"广播模式。柔性内容分发能够根据用户特征、行为数据、设备类型和上下文环境,智能地调整内容呈现方式,从而提升用户体验和内容传播效果。对于WordPress站点来说,开发一个灵活的柔性内容分发插件,可以帮助内容创作者更精准地触达目标受众。
本教程将引导您开发一个完整的WordPress柔性内容分发插件,包含用户画像分析、内容智能匹配和动态渲染等功能。
插件基础架构设计
首先,我们需要创建插件的基本结构。在WordPress的wp-content/plugins/目录下创建一个新文件夹flexible-content-distribution。
<?php
/**
* Plugin Name: 柔性内容分发系统
* Plugin URI: https://yourwebsite.com/
* Description: 基于用户画像的智能内容分发插件
* Version: 1.0.0
* Author: 您的名字
* License: GPL v2 or later
* Text Domain: flexible-content-distribution
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('FCD_VERSION', '1.0.0');
define('FCD_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('FCD_PLUGIN_URL', plugin_dir_url(__FILE__));
// 初始化插件
class FlexibleContentDistribution {
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'));
}
public function activate() {
// 创建必要的数据库表
$this->create_tables();
// 设置默认选项
$this->set_default_options();
// 刷新重写规则
flush_rewrite_rules();
}
public function deactivate() {
// 清理临时数据
delete_transient('fcd_user_profiles_cache');
// 刷新重写规则
flush_rewrite_rules();
}
public function init() {
// 加载文本域
load_plugin_textdomain('flexible-content-distribution', false, dirname(plugin_basename(__FILE__)) . '/languages');
// 加载模块
$this->load_modules();
}
private function create_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_name = $wpdb->prefix . 'fcd_user_profiles';
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id bigint(20) NOT NULL AUTO_INCREMENT,
user_id bigint(20) NOT NULL,
device_type varchar(50),
location varchar(100),
interests text,
reading_history text,
last_updated datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY user_id (user_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
private function set_default_options() {
$default_options = array(
'enable_user_tracking' => true,
'content_matching_algorithm' => 'hybrid',
'default_content_strategy' => 'popular',
'cache_duration' => 3600
);
add_option('fcd_settings', $default_options);
}
private function load_modules() {
// 加载核心模块
require_once FCD_PLUGIN_DIR . 'includes/class-user-profile.php';
require_once FCD_PLUGIN_DIR . 'includes/class-content-matcher.php';
require_once FCD_PLUGIN_DIR . 'includes/class-content-renderer.php';
// 加载管理界面
if (is_admin()) {
require_once FCD_PLUGIN_DIR . 'admin/class-admin-settings.php';
}
}
}
// 启动插件
FlexibleContentDistribution::get_instance();
?>
用户画像系统开发
用户画像是柔性内容分发的核心。我们需要收集和分析用户数据来创建个性化画像。
<?php
// 文件路径: includes/class-user-profile.php
class FCD_User_Profile {
private $user_id;
private $profile_data;
public function __construct($user_id = null) {
$this->user_id = $user_id ?: get_current_user_id();
$this->load_profile();
}
/**
* 加载用户画像数据
*/
private function load_profile() {
global $wpdb;
if ($this->user_id <= 0) {
$this->profile_data = $this->get_anonymous_profile();
return;
}
$table_name = $wpdb->prefix . 'fcd_user_profiles';
// 尝试从数据库获取
$profile = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $table_name WHERE user_id = %d",
$this->user_id
));
if ($profile) {
$this->profile_data = $this->parse_profile_data($profile);
} else {
$this->profile_data = $this->create_new_profile();
}
// 更新用户行为数据
$this->update_reading_history();
}
/**
* 为匿名用户创建基础画像
*/
private function get_anonymous_profile() {
$device_type = $this->detect_device();
$location = $this->estimate_location();
return array(
'user_id' => 0,
'device_type' => $device_type,
'location' => $location,
'interests' => array(),
'reading_history' => array(),
'user_type' => 'anonymous'
);
}
/**
* 检测用户设备类型
*/
private function detect_device() {
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
if (preg_match('/(mobile|android|iphone|ipad)/i', $user_agent)) {
return 'mobile';
} elseif (preg_match('/(tablet|ipad)/i', $user_agent)) {
return 'tablet';
} else {
return 'desktop';
}
}
/**
* 估计用户地理位置
*/
private function estimate_location() {
// 注意:在实际应用中,您需要遵守GDPR等隐私法规
// 这里使用简化版本,实际应使用IP地理定位服务
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
// 简单示例:根据IP前几位判断(实际项目请使用专业服务)
if (strpos($ip, '192.168.') === 0) {
return 'local';
}
// 默认返回未知
return 'unknown';
}
/**
* 更新用户阅读历史
*/
private function update_reading_history() {
if (is_single() && !is_admin()) {
$post_id = get_the_ID();
$category_ids = wp_get_post_categories($post_id);
if (!isset($this->profile_data['reading_history'])) {
$this->profile_data['reading_history'] = array();
}
// 添加当前文章到阅读历史
$this->profile_data['reading_history'][] = array(
'post_id' => $post_id,
'timestamp' => current_time('timestamp'),
'categories' => $category_ids
);
// 保持最近50条记录
if (count($this->profile_data['reading_history']) > 50) {
$this->profile_data['reading_history'] = array_slice(
$this->profile_data['reading_history'],
-50
);
}
// 更新兴趣标签
$this->update_interests($category_ids);
// 保存到数据库(如果是注册用户)
$this->save_profile();
}
}
/**
* 根据阅读历史更新兴趣标签
*/
private function update_interests($category_ids) {
if (!isset($this->profile_data['interests'])) {
$this->profile_data['interests'] = array();
}
foreach ($category_ids as $cat_id) {
$cat_name = get_cat_name($cat_id);
if (isset($this->profile_data['interests'][$cat_id])) {
$this->profile_data['interests'][$cat_id]['weight'] += 1;
$this->profile_data['interests'][$cat_id]['last_seen'] = current_time('timestamp');
} else {
$this->profile_data['interests'][$cat_id] = array(
'name' => $cat_name,
'weight' => 1,
'last_seen' => current_time('timestamp')
);
}
}
// 归一化权重(保持总和为100)
$total_weight = array_sum(array_column($this->profile_data['interests'], 'weight'));
if ($total_weight > 0) {
foreach ($this->profile_data['interests'] as $cat_id => $interest) {
$this->profile_data['interests'][$cat_id]['normalized_weight'] =
($interest['weight'] / $total_weight) * 100;
}
}
}
/**
* 获取用户兴趣标签
*/
public function get_top_interests($limit = 5) {
if (empty($this->profile_data['interests'])) {
return array();
}
$interests = $this->profile_data['interests'];
// 按权重排序
uasort($interests, function($a, $b) {
return $b['normalized_weight'] <=> $a['normalized_weight'];
});
// 返回前N个兴趣
return array_slice($interests, 0, $limit, true);
}
/**
* 保存用户画像到数据库
*/
public function save_profile() {
global $wpdb;
if ($this->user_id <= 0) {
return false; // 不保存匿名用户数据
}
$table_name = $wpdb->prefix . 'fcd_user_profiles';
$data = array(
'user_id' => $this->user_id,
'device_type' => $this->profile_data['device_type'],
'location' => $this->profile_data['location'],
'interests' => json_encode($this->profile_data['interests']),
'reading_history' => json_encode($this->profile_data['reading_history']),
'last_updated' => current_time('mysql')
);
$existing = $wpdb->get_var($wpdb->prepare(
"SELECT id FROM $table_name WHERE user_id = %d",
$this->user_id
));
if ($existing) {
$wpdb->update($table_name, $data, array('user_id' => $this->user_id));
} else {
$wpdb->insert($table_name, $data);
}
return true;
}
}
?>
智能内容匹配算法
有了用户画像后,我们需要开发内容匹配算法,根据用户特征推荐最合适的内容。
<?php
// 文件路径: includes/class-content-matcher.php
class FCD_Content_Matcher {
private $user_profile;
private $algorithm;
public function __construct($user_profile = null) {
$this->user_profile = $user_profile ?: new FCD_User_Profile();
$this->algorithm = get_option('fcd_settings')['content_matching_algorithm'] ?? 'hybrid';
}
/**
* 获取推荐内容
*/
public function get_recommended_posts($limit = 5, $exclude_ids = array()) {
switch ($this->algorithm) {
case 'interest_based':
return $this->get_interest_based_posts($limit, $exclude_ids);
case 'collaborative':
return $this->get_collaborative_posts($limit, $exclude_ids);
case 'hybrid':
default:
return $this->get_hybrid_recommendations($limit, $exclude_ids);
}
}
/**
* 基于兴趣的内容推荐
*/
private function get_interest_based_posts($limit, $exclude_ids) {
$interests = $this->user_profile->get_top_interests(3);
if (empty($interests)) {
return $this->get_fallback_posts($limit, $exclude_ids);
}
$interest_ids = array_keys($interests);
$args = array(
'post_type' => 'post',
'posts_per_page' => $limit * 2, // 获取更多以便筛选
'category__in' => $interest_ids,
'post__not_in' => $exclude_ids,
'orderby' => 'date',
'order' => 'DESC',
'meta_query' => array(
array(
'key' => '_thumbnail_id',
'compare' => 'EXISTS' // 优先推荐有特色图片的文章
)
)
);
$posts = get_posts($args);
// 按兴趣权重排序
usort($posts, function($a, $b) use ($interests) {
$a_cats = wp_get_post_categories($a->ID);
$b_cats = wp_get_post_categories($b->ID);
$a_score = $this->calculate_interest_score($a_cats, $interests);
$b_score = $this->calculate_interest_score($b_cats, $interests);
return $b_score <=> $a_score;
});
return array_slice($posts, 0, $limit);
}
/**
* 计算文章兴趣匹配分数
*/
private function calculate_interest_score($post_categories, $user_interests) {
$score = 0;
foreach ($post_categories as $cat_id) {
if (isset($user_interests[$cat_id])) {
$score += $user_interests[$cat_id]['normalized_weight'];
}
}
return $score;
}
/**
* 协同过滤推荐(简化版)
*/
private function get_collaborative_posts($limit, $exclude_ids) {
// 注意:完整协同过滤需要大量用户数据
// 这里实现一个简化版本
global $wpdb;
// 获取与当前用户兴趣相似的其他用户
$similar_users = $this->find_similar_users(5);
if (empty($similar_users)) {
return $this->get_fallback_posts($limit, $exclude_ids);
}
$user_ids = implode(',', $similar_users);
// 获取这些用户阅读过但当前用户未读的文章
$query = "
SELECT DISTINCT p.ID, p.post_title, COUNT(up.user_id) as read_count
FROM {$wpdb->posts} p
INNER JOIN {$wpdb->prefix}fcd_user_profiles up
ON JSON_CONTAINS(up.reading_history, CAST(p.ID AS JSON), '$')
WHERE p.post_type = 'post'
AND p.post_status = 'publish'
AND up.user_id IN ($user_ids)
AND p.ID NOT IN (
SELECT DISTINCT JSON_EXTRACT(reading_history, '$[*].post_id')
FROM {$wpdb->prefix}fcd_user_profiles
WHERE user_id = %d
)
GROUP BY p.ID
ORDER BY read_count DESC
LIMIT %d
";
$results = $wpdb->get_results($wpdb->prepare(
$query,
$this->user_profile->user_id,
$limit
));
return $results;
}
/**
* 混合推荐算法
*/
private function get_hybrid_recommendations($limit, $exclude_ids) {
$interest_posts = $this->get_interest_based_posts(ceil($limit * 0.7), $exclude_ids);
$collaborative_posts = $this->get_collaborative_posts(ceil($limit * 0.3), $exclude_ids);
$all_posts = array_merge($interest_posts, $collaborative_posts);
// 去重
$unique_posts = array();
foreach ($all_posts as $post) {
$unique_posts[$post->ID] = $post;
}
// 随机排序以避免总是相同的顺序
shuffle($unique_posts);
return array_slice($unique_posts, 0, $limit);
}
/**
* 备用推荐(当个性化推荐不足时)
*/
private function get_fallback_posts($limit, $exclude_ids) {
$args = array(
'post_type' => 'post',
'posts_per_page' => $limit,
'post__not_in' => $exclude_ids,
'orderby' => 'rand',
'meta_key' => '_fcd_popularity',
'order' => 'DESC'
);
return get_posts($args);
}
}
?>
动态内容渲染器
最后,我们需要开发内容渲染器,根据用户设备和上下文动态调整内容呈现。
<?php
// 文件路径: includes/class-content-renderer.php
class FCD_Content_Renderer {
private $user_profile;
private $content_matcher;
public function __construct() {
$this->user_profile = new FCD_User_Profile();
<?php
// 文件路径: includes/class-content-renderer.php
class FCD_Content_Renderer {
private $user_profile;
private $content_matcher;
public function __construct() {
$this->user_profile = new FCD_User_Profile();
$this->content_matcher = new FCD_Content_Matcher($this->user_profile);
// 注册短代码
add_shortcode('flexible_content', array($this, 'render_flexible_content_shortcode'));
// 在文章内容中自动插入相关内容
add_filter('the_content', array($this, 'auto_insert_related_content'), 20);
// 注册小工具
add_action('widgets_init', array($this, 'register_widgets'));
}
/**
* 渲染柔性内容分发区块
*/
public function render_flexible_content($args = array()) {
$defaults = array(
'title' => '为您推荐',
'limit' => 5,
'layout' => $this->detect_best_layout(),
'show_excerpt' => true,
'show_thumbnail' => true,
'cache_duration' => 3600
);
$args = wp_parse_args($args, $defaults);
// 生成缓存键
$cache_key = 'fcd_content_' . md5(serialize($args) . $this->user_profile->user_id);
// 尝试从缓存获取
$cached_content = get_transient($cache_key);
if ($cached_content !== false) {
return $cached_content;
}
// 获取推荐内容
$exclude_ids = is_single() ? array(get_the_ID()) : array();
$recommended_posts = $this->content_matcher->get_recommended_posts($args['limit'], $exclude_ids);
if (empty($recommended_posts)) {
return '<p class="fcd-no-content">暂无推荐内容</p>';
}
// 根据布局渲染内容
$output = $this->render_by_layout($recommended_posts, $args);
// 缓存结果
set_transient($cache_key, $output, $args['cache_duration']);
return $output;
}
/**
* 检测最佳布局
*/
private function detect_best_layout() {
$device_type = $this->user_profile->device_type;
switch ($device_type) {
case 'mobile':
return 'list_compact';
case 'tablet':
return 'grid_2col';
default:
return 'grid_3col';
}
}
/**
* 根据布局渲染内容
*/
private function render_by_layout($posts, $args) {
$layout_method = 'render_' . $args['layout'];
if (method_exists($this, $layout_method)) {
return $this->$layout_method($posts, $args);
}
// 默认使用网格布局
return $this->render_grid_3col($posts, $args);
}
/**
* 渲染紧凑列表布局(适合移动端)
*/
private function render_list_compact($posts, $args) {
$output = '<div class="fcd-container fcd-layout-list-compact">';
if (!empty($args['title'])) {
$output .= '<h3 class="fcd-title">' . esc_html($args['title']) . '</h3>';
}
$output .= '<div class="fcd-list">';
foreach ($posts as $post) {
$output .= $this->render_list_item($post, $args);
}
$output .= '</div></div>';
return $output;
}
/**
* 渲染网格布局(适合桌面端)
*/
private function render_grid_3col($posts, $args) {
$output = '<div class="fcd-container fcd-layout-grid-3col">';
if (!empty($args['title'])) {
$output .= '<h3 class="fcd-title">' . esc_html($args['title']) . '</h3>';
}
$output .= '<div class="fcd-grid">';
foreach ($posts as $post) {
$output .= $this->render_grid_item($post, $args);
}
$output .= '</div></div>';
return $output;
}
/**
* 渲染列表项
*/
private function render_list_item($post, $args) {
$permalink = get_permalink($post->ID);
$title = get_the_title($post->ID);
$excerpt = $args['show_excerpt'] ? $this->get_adaptive_excerpt($post) : '';
$output = '<div class="fcd-list-item">';
if ($args['show_thumbnail']) {
$thumbnail = $this->get_adaptive_thumbnail($post->ID);
if ($thumbnail) {
$output .= '<div class="fcd-thumbnail">';
$output .= '<a href="' . esc_url($permalink) . '">' . $thumbnail . '</a>';
$output .= '</div>';
}
}
$output .= '<div class="fcd-content">';
$output .= '<h4 class="fcd-post-title"><a href="' . esc_url($permalink) . '">' . esc_html($title) . '</a></h4>';
if ($excerpt) {
$output .= '<div class="fcd-excerpt">' . $excerpt . '</div>';
}
// 显示相关性标签
$relevance = $this->calculate_relevance_label($post);
if ($relevance) {
$output .= '<span class="fcd-relevance-label">' . esc_html($relevance) . '</span>';
}
$output .= '</div></div>';
return $output;
}
/**
* 渲染网格项
*/
private function render_grid_item($post, $args) {
$permalink = get_permalink($post->ID);
$title = get_the_title($post->ID);
$excerpt = $args['show_excerpt'] ? $this->get_adaptive_excerpt($post) : '';
$output = '<div class="fcd-grid-item">';
if ($args['show_thumbnail']) {
$thumbnail = $this->get_adaptive_thumbnail($post->ID);
if ($thumbnail) {
$output .= '<div class="fcd-thumbnail">';
$output .= '<a href="' . esc_url($permalink) . '">' . $thumbnail . '</a>';
$output .= '</div>';
}
}
$output .= '<div class="fcd-content">';
$output .= '<h4 class="fcd-post-title"><a href="' . esc_url($permalink) . '">' . esc_html($title) . '</a></h4>';
if ($excerpt) {
$output .= '<div class="fcd-excerpt">' . $excerpt . '</div>';
}
$output .= '</div></div>';
return $output;
}
/**
* 获取自适应摘要(根据设备调整长度)
*/
private function get_adaptive_excerpt($post) {
$excerpt_length = $this->user_profile->device_type === 'mobile' ? 60 : 100;
if (!empty($post->post_excerpt)) {
$excerpt = $post->post_excerpt;
} else {
$excerpt = wp_strip_all_tags($post->post_content);
}
$excerpt = wp_trim_words($excerpt, $excerpt_length, '...');
return '<p>' . esc_html($excerpt) . '</p>';
}
/**
* 获取自适应缩略图(根据设备调整尺寸)
*/
private function get_adaptive_thumbnail($post_id) {
$device_type = $this->user_profile->device_type;
switch ($device_type) {
case 'mobile':
$size = 'medium';
break;
case 'tablet':
$size = 'medium_large';
break;
default:
$size = 'large';
}
if (has_post_thumbnail($post_id)) {
return get_the_post_thumbnail($post_id, $size, array(
'class' => 'fcd-thumb-img',
'loading' => 'lazy',
'alt' => get_the_title($post_id)
));
}
// 如果没有特色图片,返回默认图片
return '<img src="' . FCD_PLUGIN_URL . 'assets/default-thumbnail.jpg"
class="fcd-thumb-img fcd-default-thumb"
alt="' . esc_attr__('默认缩略图', 'flexible-content-distribution') . '">';
}
/**
* 计算相关性标签
*/
private function calculate_relevance_label($post) {
// 这里可以根据用户画像和文章特征的匹配度返回标签
// 例如:"与您兴趣高度匹配"、"热门内容"、"最新发布"等
$post_date = get_the_date('U', $post->ID);
$days_old = (current_time('timestamp') - $post_date) / DAY_IN_SECONDS;
if ($days_old < 3) {
return '最新发布';
}
// 检查是否是热门内容
$views = get_post_meta($post->ID, 'post_views_count', true);
if ($views > 1000) {
return '热门内容';
}
return '';
}
/**
* 短代码处理函数
*/
public function render_flexible_content_shortcode($atts) {
$atts = shortcode_atts(array(
'title' => '为您推荐',
'limit' => 5,
'layout' => 'auto',
'show_excerpt' => true,
'show_thumbnail' => true
), $atts, 'flexible_content');
if ($atts['layout'] === 'auto') {
unset($atts['layout']);
}
return $this->render_flexible_content($atts);
}
/**
* 自动在文章内容后插入相关内容
*/
public function auto_insert_related_content($content) {
if (!is_single() || !is_main_query()) {
return $content;
}
$settings = get_option('fcd_settings', array());
if (empty($settings['auto_insert_content'])) {
return $content;
}
$related_content = $this->render_flexible_content(array(
'title' => $settings['related_content_title'] ?? '相关推荐',
'limit' => $settings['related_content_limit'] ?? 3,
'layout' => 'list_compact'
));
return $content . $related_content;
}
/**
* 注册小工具
*/
public function register_widgets() {
require_once FCD_PLUGIN_DIR . 'includes/class-fcd-widget.php';
register_widget('FCD_Flexible_Content_Widget');
}
}
// 初始化渲染器
new FCD_Content_Renderer();
?>
管理界面开发
为了让网站管理员能够配置插件,我们需要开发一个管理界面。
<?php
// 文件路径: admin/class-admin-settings.php
class FCD_Admin_Settings {
private $settings_page;
public function __construct() {
add_action('admin_menu', array($this, 'add_admin_menu'));
add_action('admin_init', array($this, 'register_settings'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
}
/**
* 添加管理菜单
*/
public function add_admin_menu() {
$this->settings_page = add_menu_page(
'柔性内容分发设置',
'内容分发',
'manage_options',
'fcd-settings',
array($this, 'render_settings_page'),
'dashicons-share',
30
);
// 添加子菜单
add_submenu_page(
'fcd-settings',
'用户画像分析',
'用户画像',
'manage_options',
'fcd-user-profiles',
array($this, 'render_user_profiles_page')
);
add_submenu_page(
'fcd-settings',
'内容匹配统计',
'匹配统计',
'manage_options',
'fcd-analytics',
array($this, 'render_analytics_page')
);
}
/**
* 注册设置选项
*/
public function register_settings() {
register_setting('fcd_settings_group', 'fcd_settings', array(
'sanitize_callback' => array($this, 'sanitize_settings')
));
// 基本设置部分
add_settings_section(
'fcd_basic_settings',
'基本设置',
array($this, 'render_basic_settings_section'),
'fcd-settings'
);
add_settings_field(
'enable_user_tracking',
'启用用户追踪',
array($this, 'render_enable_user_tracking_field'),
'fcd-settings',
'fcd_basic_settings'
);
add_settings_field(
'content_matching_algorithm',
'内容匹配算法',
array($this, 'render_algorithm_field'),
'fcd-settings',
'fcd_basic_settings'
);
// 显示设置部分
add_settings_section(
'fcd_display_settings',
'显示设置',
array($this, 'render_display_settings_section'),
'fcd-settings'
);
add_settings_field(
'auto_insert_content',
'自动插入相关内容',
array($this, 'render_auto_insert_field'),
'fcd-settings',
'fcd_display_settings'
);
add_settings_field(
'related_content_title',
'相关内容标题',
array($this, 'render_related_title_field'),
'fcd-settings',
'fcd_display_settings'
);
}
/**
* 清理设置数据
*/
public function sanitize_settings($input) {
$sanitized = array();
// 清理布尔值
$sanitized['enable_user_tracking'] = isset($input['enable_user_tracking']) ? 1 : 0;
$sanitized['auto_insert_content'] = isset($input['auto_insert_content']) ? 1 : 0;
// 清理算法选择
$allowed_algorithms = array('interest_based', 'collaborative', 'hybrid');
$sanitized['content_matching_algorithm'] = in_array($input['content_matching_algorithm'], $allowed_algorithms)
? $input['content_matching_algorithm']
: 'hybrid';
// 清理文本字段
$sanitized['related_content_title'] = sanitize_text_field($input['related_content_title'] ?? '相关推荐');
$sanitized['related_content_limit'] = absint($input['related_content_limit'] ?? 3);
return $sanitized;
}
/**
* 渲染设置页面
*/
public function render_settings_page() {
if (!current_user_can('manage_options')) {
return;
}
?>
<div class="wrap">
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
<form action="options.php" method="post">
<?php
settings_fields('fcd_settings_group');
do_settings_sections('fcd-settings');
submit_button('保存设置');
?>
</form>
<div class="fcd-admin-info">
<h3>插件使用说明</h3>
<p>1. 在文章或页面中使用短代码 <code>[flexible_content]</code> 显示推荐内容</p>
<p>2. 可以通过小工具区域添加"柔性内容分发"小工具</p>
<p>3. 支持的自定义参数:title, limit, layout, show_excerpt, show_thumbnail</p>
<p>示例:<code>[flexible_content title="猜你喜欢" limit="4" layout="grid_2col"]</code></p>
</div>
</div>
<?php
}
/**
* 渲染用户画像页面
*/
public function render_user_profiles_page() {
global $wpdb;
$table_name = $wpdb->prefix . 'fcd_user_profiles';
$profiles = $wpdb->get_results("SELECT * FROM $table_name ORDER BY last_updated DESC LIMIT 50");
?>
<div class="wrap">
<h1>用户画像分析</h1>
<div class="fcd-stats-summary">
<div class="fcd-stat-box">
<h3>总用户画像数</h3>
<p><?php echo $wpdb->get_var("SELECT COUNT(*) FROM $table_name"); ?></p>
</div>
<div class="fcd-stat-box">
<h3>今日活跃用户</h3>
<p><?php echo $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(DISTINCT user_id) FROM $table_name WHERE DATE(last_updated) = %s",
current_time('Y-m-d')
)); ?></p>
</div>
</div>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th>用户ID</th>
<th>设备类型</th>
<th>位置</th>
<th>兴趣标签</th>
<th>最后更新</th>
</tr>
</thead>
<tbody>
<?php foreach ($profiles as $profile): ?>
<tr>
<td>
<?php
$user = get_user_by('id', $profile->user_id);
