文章目录
-
- 在当今网络传媒环境中,内容分发不再局限于简单的"一对多"广播模式。柔性内容分发能够根据用户特征、行为数据、设备类型和上下文环境,智能地调整内容呈现方式,从而提升用户体验和内容传播效果。对于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);
在当今网络传媒环境中,内容分发不再局限于简单的"一对多"广播模式。柔性内容分发能够根据用户特征、行为数据、设备类型和上下文环境,智能地调整内容呈现方式,从而提升用户体验和内容传播效果。对于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);


