Files
Collection/Plugin.php

2029 lines
71 KiB
PHP
Raw Permalink Normal View History

2026-02-23 17:19:04 +08:00
<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
/**
* 合集插件 - 创建专题合集,支持短代码展示
*
* @package Collection
* @author 石头厝
* @version 1.2.0
* @link https://www.shitoucuo.com/
*/
class Collection_Plugin implements Typecho_Plugin_Interface
{
/**
* 数据库文件路径
*/
private static $dbPath;
/**
* 是否已添加CSS样式
*/
private static $cssAdded = false;
/**
* 是否已添加JS脚本
*/
private static $jsAdded = false;
/**
* 合集配置数组
*/
private static $collectionConfigs = array();
/**
* 激活插件方法
*/
public static function activate()
{
// 初始化数据库
self::initDbPath();
self::initDatabase();
self::migrateDatabase();
// 添加后台管理菜单
Helper::addPanel(3, 'Collection/Manage.php', '合集管理', '合集管理', 'administrator');
// 添加动作处理
Helper::addAction('collection', 'Collection_Action');
// 注册路由
Helper::addRoute('collection_action', '/action/collection', 'Collection_Action', 'action');
// 注册短代码解析
Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = array(__CLASS__, 'parseCollectionShortcode');
Typecho_Plugin::factory('Widget_Abstract_Contents')->excerptEx = array(__CLASS__, 'parseCollectionShortcode');
// 注册文章保存时的处理
Typecho_Plugin::factory('Widget_Abstract_Contents')->save = array(__CLASS__, 'onPostSave');
Typecho_Plugin::factory('Widget_Abstract_Contents')->write = array(__CLASS__, 'onPostWrite');
// 只保留footer钩子来输出JS移除header钩子
Typecho_Plugin::factory('Widget_Archive')->footer = array(__CLASS__, 'footer');
return _t('合集插件已激活');
}
/**
* 禁用插件方法
*/
public static function deactivate()
{
// 移除管理菜单
Helper::removePanel(3, 'Collection/Manage.php');
// 清理数据库记录
try {
$db = Typecho_Db::get();
$db->query($db->delete('table.options')
->where('name = ?', 'panelTable:Collection/Manage.php'));
} catch (Exception $e) {
// 忽略错误
}
Helper::removeAction('collection');
Helper::removeRoute('collection_action');
return _t('合集插件已禁用');
}
/**
* 获取插件配置面板
*/
public static function config(Typecho_Widget_Helper_Form $form)
{
// 显示模式
$displayMode = new Typecho_Widget_Helper_Form_Element_Radio('displayMode', array(
'collapsible' => '可折叠模式(默认)',
'expanded' => '始终展开',
'grid' => '网格布局'
), 'collapsible', _t('合集展示模式'));
$form->addInput($displayMode);
// 是否显示发布时间
$showDate = new Typecho_Widget_Helper_Form_Element_Radio('showDate', array(
1 => '是',
0 => '否'
), 1, _t('显示内容发布时间'));
$form->addInput($showDate);
// 是否显示内容摘要
$showExcerpt = new Typecho_Widget_Helper_Form_Element_Radio('showExcerpt', array(
1 => '是',
0 => '否'
), 1, _t('显示内容摘要'));
$form->addInput($showExcerpt);
// 是否显示评论数
$showCommentCount = new Typecho_Widget_Helper_Form_Element_Radio('showCommentCount', array(
1 => '是',
0 => '否'
), 1, _t('显示评论数'));
$form->addInput($showCommentCount);
// 默认排序方式
$defaultSort = new Typecho_Widget_Helper_Form_Element_Select('defaultSort', array(
'created_desc' => '发布时间倒序',
'created_asc' => '发布时间正序',
'title_asc' => '标题正序',
'title_desc' => '标题倒序',
'custom' => '自定义顺序'
), 'created_desc', _t('内容默认排序'));
$form->addInput($defaultSort);
}
/**
* 个人用户的配置面板
*/
public static function personalConfig(Typecho_Widget_Helper_Form $form) {}
/**
* 初始化数据库路径
*/
private static function initDbPath()
{
$dbDir = __DIR__ . '/db';
// 确保目录存在
if (!is_dir($dbDir)) {
@mkdir($dbDir, 0755, true);
}
$dbFiles = glob($dbDir . '/collection_*.db');
if (!empty($dbFiles)) {
self::$dbPath = $dbFiles[0];
} else {
$randomStr = substr(md5(uniqid(rand(), true)), 0, 10);
self::$dbPath = $dbDir . '/collection_' . $randomStr . '.db';
}
}
/**
* 初始化数据库
*/
private static function initDatabase()
{
if (empty(self::$dbPath)) {
self::initDbPath();
}
try {
$db = new PDO('sqlite:' . self::$dbPath);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 检查表是否存在
$tableCheck = $db->query("SELECT name FROM sqlite_master WHERE type='table' AND name='plugin_collection'");
if (!$tableCheck->fetch()) {
// 创建表
$db->exec("CREATE TABLE plugin_collection (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
description TEXT,
related_items TEXT,
sort_order TEXT DEFAULT 'created_desc',
collection_type TEXT DEFAULT 'article',
is_active INTEGER DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)");
// 创建更新时间触发器
$db->exec("CREATE TRIGGER IF NOT EXISTS update_collection_time
AFTER UPDATE ON plugin_collection
BEGIN
UPDATE plugin_collection SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
END");
}
$db = null;
} catch (PDOException $e) {
error_log('Collection: 数据库初始化失败: ' . $e->getMessage());
}
}
/**
* 数据库迁移
*/
private static function migrateDatabase()
{
try {
$db = new PDO('sqlite:' . self::$dbPath);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 检查表结构
$stmt = $db->prepare("PRAGMA table_info(plugin_collection)");
$stmt->execute();
$columns = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 检查字段是否存在
$hasSortOrder = false;
$hasIsActive = false;
$hasCollectionType = false;
foreach ($columns as $column) {
if ($column['name'] === 'sort_order') {
$hasSortOrder = true;
}
if ($column['name'] === 'is_active') {
$hasIsActive = true;
}
if ($column['name'] === 'collection_type') {
$hasCollectionType = true;
}
}
// 添加缺失的字段
if (!$hasSortOrder) {
$db->exec("ALTER TABLE plugin_collection ADD COLUMN sort_order TEXT DEFAULT 'created_desc'");
}
if (!$hasIsActive) {
$db->exec("ALTER TABLE plugin_collection ADD COLUMN is_active INTEGER DEFAULT 1");
}
if (!$hasCollectionType) {
$db->exec("ALTER TABLE plugin_collection ADD COLUMN collection_type TEXT DEFAULT 'article'");
// 重命名相关字段
try {
$db->exec("ALTER TABLE plugin_collection RENAME COLUMN related_articles TO related_items");
} catch (Exception $e) {
// 如果重命名失败,可能是已经存在或者已经重命名过了
}
}
$db = null;
} catch (PDOException $e) {
error_log('Collection数据库迁移失败: ' . $e->getMessage());
}
}
/**
* 获取数据库连接
*/
public static function getDbConnection()
{
if (empty(self::$dbPath)) {
self::initDbPath();
}
if (!file_exists(self::$dbPath)) {
self::initDatabase();
}
try {
$db = new PDO('sqlite:' . self::$dbPath);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $db;
} catch (PDOException $e) {
throw new Exception('数据库连接失败: ' . $e->getMessage());
}
}
/**
* 通过合集ID获取合集信息
*/
public static function getCollectionById($id)
{
if (empty($id)) {
return null;
}
try {
$db = self::getDbConnection();
$stmt = $db->prepare("SELECT * FROM plugin_collection WHERE id = ? AND is_active = 1");
$stmt->execute(array($id));
$collection = $stmt->fetch(PDO::FETCH_ASSOC);
if ($collection) {
// 处理关联内容
if (!empty($collection['related_items'])) {
$itemIds = explode(',', $collection['related_items']);
$itemIds = array_map('trim', $itemIds);
$itemIds = array_filter($itemIds);
if ($collection['collection_type'] == 'comment') {
// 获取关联评论信息
$commentsInfo = array();
foreach ($itemIds as $coid) {
if (is_numeric($coid)) {
$commentInfo = self::getCommentInfo($coid);
if (!empty($commentInfo['author'])) {
$commentsInfo[] = array(
'author' => $commentInfo['author'],
'content' => $commentInfo['text'],
'created' => $commentInfo['created'],
'link' => $commentInfo['link'],
'excerpt' => self::getExcerpt($commentInfo['text']),
'coid' => $coid,
'url' => $commentInfo['url'] // 用户网站链接
);
}
}
}
$collection['related_items_info'] = $commentsInfo;
} elseif ($collection['collection_type'] == 'user') {
// 获取关联用户信息
$usersInfo = array();
foreach ($itemIds as $uid) {
if (is_numeric($uid)) {
$userInfo = self::getUserInfo($uid);
if (!empty($userInfo['name'])) {
$usersInfo[] = array(
'name' => $userInfo['name'],
'url' => $userInfo['url'],
'created' => $userInfo['created'],
'commentCount' => $userInfo['commentCount'],
'recentActivity' => $userInfo['recentActivity'],
'uid' => $uid
);
}
}
}
$collection['related_items_info'] = $usersInfo;
} else {
// 获取关联文章信息
$articlesInfo = array();
foreach ($itemIds as $cid) {
if (is_numeric($cid)) {
$articleInfo = self::getArticleInfo($cid);
if (!empty($articleInfo['title'])) {
$articlesInfo[] = array(
'title' => $articleInfo['title'],
'link' => $articleInfo['link'],
'created' => $articleInfo['created'],
'excerpt' => self::getExcerpt($articleInfo['text']),
'cover' => !empty($articleInfo['images']) ? $articleInfo['images'][0] : '',
'commentCount' => self::getArticleCommentCount($cid),
'cid' => $cid
);
}
}
}
$collection['related_items_info'] = $articlesInfo;
}
// 根据排序方式排序
$collection['related_items_info'] = self::sortItems($collection['related_items_info'], $collection['sort_order'], $collection['collection_type']);
}
return $collection;
}
} catch (Exception $e) {
error_log('Collection: 获取合集信息失败: ' . $e->getMessage());
}
return null;
}
/**
* 获取所有合集
*/
public static function getAllCollections()
{
try {
$db = self::getDbConnection();
$stmt = $db->query("SELECT * FROM plugin_collection WHERE is_active = 1 ORDER BY collection_type, created_at DESC");
$collections = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $collections;
} catch (Exception $e) {
error_log('Collection: 获取所有合集失败: ' . $e->getMessage());
return array();
}
}
/**
* 通过文章CID获取文章信息和图片
*/
public static function getArticleInfo($cid)
{
$result = array(
'title' => '',
'link' => '',
'text' => '',
'images' => array(),
'tags' => array(),
'created' => ''
);
if (empty($cid)) {
return $result;
}
try {
$db = Typecho_Db::get();
$prefix = $db->getPrefix();
// 使用Typecho_Db的正确查询方法
$article = $db->fetchRow($db->select()
->from('table.contents')
->where('cid = ?', $cid)
->where('type = ?', 'post')
->where('status = ?', 'publish')
->limit(1));
if ($article) {
$result['title'] = $article['title'];
$result['link'] = self::getPostUrlByCid($cid);
$result['text'] = $article['text'];
$result['created'] = $article['created'];
$result['images'] = self::getPostImagesByCid($cid);
$result['tags'] = self::getPostTagsByCid($cid);
}
} catch (Exception $e) {
error_log('Collection: 获取文章信息失败: ' . $e->getMessage());
}
return $result;
}
/**
* 通过评论COID获取评论信息
*/
public static function getCommentInfo($coid)
{
$result = array(
'author' => '',
'text' => '',
'link' => '',
'created' => '',
'parent' => '',
'mail' => '',
'url' => ''
);
if (empty($coid)) {
return $result;
}
try {
$db = Typecho_Db::get();
// 获取评论信息
$comment = $db->fetchRow($db->select()
->from('table.comments')
->where('coid = ?', $coid)
->where('status = ?', 'approved')
->limit(1));
if ($comment) {
$result['author'] = $comment['author'];
$result['text'] = $comment['text'];
$result['created'] = $comment['created'];
$result['mail'] = $comment['mail'];
$result['url'] = $comment['url'];
$result['parent'] = $comment['parent'];
// 获取评论所属文章信息以生成链接
$post = $db->fetchRow($db->select('slug', 'type', 'created')
->from('table.contents')
->where('cid = ?', $comment['cid']));
if ($post) {
$result['link'] = self::getPostUrlByCid($comment['cid']) . '#comment-' . $coid;
}
}
} catch (Exception $e) {
error_log('Collection: 获取评论信息失败: ' . $e->getMessage());
}
return $result;
}
/**
* 通过用户UID获取用户信息
*/
public static function getUserInfo($uid)
{
$result = array(
'name' => '',
'url' => '',
'mail' => '',
'created' => '',
'recentActivity' => '',
'commentCount' => 0
);
if (empty($uid)) {
return $result;
}
try {
$db = Typecho_Db::get();
// 获取用户信息
$user = $db->fetchRow($db->select()
->from('table.users')
->where('uid = ?', $uid)
->limit(1));
if ($user) {
$result['name'] = $user['name'];
$result['url'] = $user['url'];
$result['mail'] = $user['mail'];
$result['created'] = $user['created'];
// 获取用户最近活跃时间(如果有的话)
if (isset($user['logged']) && $user['logged']) {
$result['recentActivity'] = date('Y-m-d', $user['logged']);
} elseif (isset($user['activated']) && $user['activated']) {
$result['recentActivity'] = date('Y-m-d', $user['activated']);
}
// 获取用户评论总数 - 修复语法错误
$commentCountQuery = $db->select('COUNT(*)')
->from('table.comments')
->where('authorId = ?', $uid)
->where('status = ?', 'approved');
$commentCount = $db->fetchRow($commentCountQuery);
if ($commentCount) {
$result['commentCount'] = intval($commentCount['COUNT(*)']);
}
}
} catch (Exception $e) {
error_log('Collection: 获取用户信息失败: ' . $e->getMessage());
}
return $result;
}
/**
* 获取文章评论数
*/
private static function getArticleCommentCount($cid)
{
try {
$db = Typecho_Db::get();
$countQuery = $db->select('COUNT(*)')
->from('table.comments')
->where('cid = ?', $cid)
->where('status = ?', 'approved');
$count = $db->fetchRow($countQuery);
return $count ? intval($count['COUNT(*)']) : 0;
} catch (Exception $e) {
error_log('Collection: 获取文章评论数失败: ' . $e->getMessage());
return 0;
}
}
/**
* 通过文章CID获取文章URL
*/
public static function getPostUrlByCid($cid)
{
try {
$db = Typecho_Db::get();
$row = $db->fetchRow($db->select('slug', 'type', 'created')
->from('table.contents')
->where('cid = ?', $cid)
->where('status = ?', 'publish'));
if (!$row) {
return '';
}
// 获取文章分类
$category = '';
$categories = $db->fetchAll($db->select('slug')
->from('table.metas')
->join('table.relationships', 'table.metas.mid = table.relationships.mid')
->where('table.relationships.cid = ?', $cid)
->where('table.metas.type = ?', 'category')
->order('table.metas.order', Typecho_Db::SORT_ASC));
if (!empty($categories)) {
$category = $categories[0]['slug'];
}
// 准备URL参数
$date = getdate($row['created']);
$params = array(
'cid' => $cid,
'slug' => $row['slug'],
'category' => $category,
'directory' => $category,
'year' => $date['year'],
'month' => str_pad($date['mon'], 2, '0', STR_PAD_LEFT),
'day' => str_pad($date['mday'], 2, '0', STR_PAD_LEFT)
);
$options = Typecho_Widget::widget('Widget_Options');
$permalinkStructure = '';
if (isset($options->permalink)) {
$permalinkStructure = $options->permalink;
}
if (empty($permalinkStructure)) {
return Typecho_Router::url($row['type'], $row, $options->index);
}
$url = $permalinkStructure;
$url = preg_replace('/\[year:digital:4\]/', $params['year'], $url);
$url = preg_replace('/\[month:digital:2\]/', $params['month'], $url);
$url = preg_replace('/\[day:digital:2\]/', $params['day'], $url);
$url = preg_replace('/\[slug\]/', $params['slug'], $url);
$url = preg_replace('/\[cid\]/', $params['cid'], $url);
$url = preg_replace('/\[category\]/', $params['category'], $url);
$url = preg_replace('/\[directory\]/', $params['directory'], $url);
if (strpos($url, '/') !== 0) {
$url = '/' . $url;
}
return rtrim($options->siteUrl, '/') . $url;
} catch (Exception $e) {
error_log("Collection: 获取文章 URL 失败: " . $e->getMessage());
}
return '';
}
/**
* 通过文章CID获取文章中的图片
*/
public static function getPostImagesByCid($cid)
{
try {
$db = Typecho_Db::get();
$content = $db->fetchRow($db->select('text')
->from('table.contents')
->where('cid = ?', $cid)
->where('type = ?', 'post')
->where('status = ?', 'publish'));
if (!$content) {
return array();
}
$images = array();
$text = $content['text'];
// 标准img标签
preg_match_all('/<img[^>]+src=[\'"]([^\'"]+)[\'"][^>]*>/i', $text, $matches1);
if (isset($matches1[1]) && !empty($matches1[1])) {
foreach($matches1[1] as $imageUrl) {
$images[] = self::processImageUrl($imageUrl);
}
}
// markdown图片语法
preg_match_all('/!\[[^\]]*\]\(([^)]+)\)/i', $text, $matches2);
if (isset($matches2[1]) && !empty($matches2[1])) {
foreach($matches2[1] as $imageUrl) {
$images[] = self::processImageUrl($imageUrl);
}
}
// 去重并过滤空值
$images = array_filter(array_unique($images));
$images = array_slice($images, 0, 4);
return $images;
} catch (Exception $e) {
error_log('Collection: 获取文章图片失败: ' . $e->getMessage());
return array();
}
}
/**
* 处理图片URL
*/
private static function processImageUrl($imageUrl)
{
if (strpos($imageUrl, 'http') !== 0) {
$options = Typecho_Widget::widget('Widget_Options');
$imageUrl = Typecho_Common::url($imageUrl, $options->siteUrl);
}
return $imageUrl;
}
/**
* 通过文章CID获取文章标签
*/
public static function getPostTagsByCid($cid)
{
try {
$db = Typecho_Db::get();
$tags = $db->fetchAll($db->select('table.metas.name', 'table.metas.slug')
->from('table.metas')
->join('table.relationships', 'table.metas.mid = table.relationships.mid')
->where('table.relationships.cid = ?', $cid)
->where('table.metas.type = ?', 'tag')
->order('table.metas.order', Typecho_Db::SORT_ASC));
$tagNames = array();
if (!empty($tags)) {
foreach ($tags as $tag) {
$tagNames[] = $tag['name'];
}
}
return $tagNames;
} catch (Exception $e) {
error_log('Collection: 获取文章标签失败: ' . $e->getMessage());
return array();
}
}
/**
* 获取内容摘要
*/
private static function getExcerpt($content, $length = 100)
{
$text = strip_tags($content);
$text = preg_replace('/\s+/', ' ', $text);
if (mb_strlen($text, 'UTF-8') > $length) {
$text = mb_substr($text, 0, $length, 'UTF-8') . '...';
}
return $text;
}
/**
* 排序内容
*/
private static function sortItems($items, $sortOrder, $collectionType)
{
if (empty($items) || count($items) <= 1) {
return $items;
}
usort($items, function($a, $b) use ($sortOrder, $collectionType) {
switch($sortOrder) {
case 'created_desc':
return ($b['created'] ?? 0) - ($a['created'] ?? 0);
case 'created_asc':
return ($a['created'] ?? 0) - ($b['created'] ?? 0);
case 'title_asc':
if ($collectionType === 'user') {
return strcmp($a['name'] ?? '', $b['name'] ?? '');
} else {
return strcmp($a['title'] ?? '', $b['title'] ?? '');
}
case 'title_desc':
if ($collectionType === 'user') {
return strcmp($b['name'] ?? '', $a['name'] ?? '');
} else {
return strcmp($b['title'] ?? '', $a['title'] ?? '');
}
case 'name_asc':
return strcmp($a['name'] ?? '', $b['name'] ?? '');
case 'name_desc':
return strcmp($b['name'] ?? '', $a['name'] ?? '');
case 'comments_desc':
return ($b['commentCount'] ?? 0) - ($a['commentCount'] ?? 0);
case 'comments_asc':
return ($a['commentCount'] ?? 0) - ($b['commentCount'] ?? 0);
default:
// 自定义顺序保持原样
return 0;
}
});
return $items;
}
/**
* 解析文章内容中的合集短代码
*/
public static function parseCollectionShortcode($content, $widget, $lastResult)
{
$content = empty($lastResult) ? $content : $lastResult;
$pattern = '/\{collection-(\d+)\}/i';
if (preg_match_all($pattern, $content, $matches)) {
$currentCid = isset($widget->cid) ? $widget->cid : 0;
// 收集所有需要渲染的合集ID
$collectionIds = $matches[1];
$collectionIndex = 0;
foreach ($collectionIds as $index => $collectionId) {
// 渲染单个合集卡片同时获取CSS样式
list($collectionHtml, $cssStyle, $config) = self::renderSingleCollectionCard($collectionId, $collectionIndex);
if ($collectionHtml) {
// 将CSS内联到HTML中避免与足迹地图冲突
$collectionHtml = '<style>' . $cssStyle . '</style>' . $collectionHtml;
$content = str_replace($matches[0][$index], $collectionHtml, $content);
if ($config) {
self::$collectionConfigs[] = $config;
}
if ($currentCid > 0) {
self::syncRelatedItems($collectionId, $currentCid, 'article');
}
} else {
$content = str_replace($matches[0][$index],
'<div class="collection-error">合集ID ' . $collectionId . ' 不存在</div>',
$content);
}
$collectionIndex++;
}
}
return $content;
}
/**
* 渲染单个合集卡片HTML
*/
private static function renderSingleCollectionCard($collectionId, $index)
{
$collection = self::getCollectionById($collectionId);
if (!$collection) {
return array(null, null, null);
}
$options = Typecho_Widget::widget('Widget_Options')->plugin('Collection');
$displayMode = isset($options->displayMode) ? $options->displayMode : 'collapsible';
$showDate = isset($options->showDate) ? (bool)$options->showDate : true;
$showExcerpt = isset($options->showExcerpt) ? (bool)$options->showExcerpt : true;
$showCommentCount = isset($options->showCommentCount) ? (bool)$options->showCommentCount : true;
$items = isset($collection['related_items_info']) ? $collection['related_items_info'] : array();
$itemsCount = count($items);
$collectionType = $collection['collection_type'];
$uniqueId = 'collection_' . $collectionId . '_' . $index;
$collectionCardId = 'collection-card-' . $uniqueId;
// 构建统计文本 - 根据合集类型使用正确的量词
$countText = '';
if ($collectionType === 'comment') {
$countText = '已收录' . $itemsCount . '条评论';
} elseif ($collectionType === 'user') {
$countText = '已收录' . $itemsCount . '位用户';
} else {
$countText = '已收录' . $itemsCount . '篇文章';
}
$html = '
<div class="collection-card" id="' . $collectionCardId . '" data-collection-id="' . $collectionId . '" data-display-mode="' . $displayMode . '" data-collection-type="' . $collectionType . '">
<div class="collection-header">
<div class="collection-title-row">
<div class="collection-title">' . htmlspecialchars($collection['name']) . '</div>
<div class="collection-count">' . $countText . '</div>
</div>';
if ($collection['description']) {
$html .= '<div class="collection-description">' . nl2br(htmlspecialchars($collection['description'])) . '</div>';
}
$html .= '</div>';
if ($itemsCount === 1) {
$item = reset($items);
if ($collectionType === 'comment') {
$authorLink = !empty($item['url']) ?
'<a href="' . htmlspecialchars($item['url']) . '" target="_blank" class="author-link">' . htmlspecialchars($item['author']) . '</a>' :
htmlspecialchars($item['author']);
$html .= '
<div class="collection-single-item">
<div class="item-info">
<div class="item-content-link">
<a href="' . htmlspecialchars($item['link']) . '" target="_blank" class="comment-link">' . htmlspecialchars($item['excerpt']) . '</a>
</div>
<div class="comment-meta">
<div class="comment-author">' . $authorLink . '</div>';
if ($showDate && isset($item['created']) && $item['created']) {
$date = date('Y-m-d', $item['created']);
$html .= '<div class="comment-date">评论于 ' . $date . '</div>';
}
$html .= '
</div>
</div>
</div>';
} elseif ($collectionType === 'user') {
$userNameLink = !empty($item['url']) ?
'<a href="' . htmlspecialchars($item['url']) . '" target="_blank" class="user-link">' . htmlspecialchars($item['name']) . '</a>' :
htmlspecialchars($item['name']);
$html .= '
<div class="collection-single-item">
<div class="item-info">
<div class="item-name">用户:' . $userNameLink . '</div>';
if ($showDate && isset($item['created']) && $item['created']) {
$date = date('Y-m-d', $item['created']);
$html .= '<div class="item-date">注册于 ' . $date . '</div>';
}
if (isset($item['recentActivity']) && $item['recentActivity']) {
$html .= '<div class="item-activity">最近活跃:' . $item['recentActivity'] . '</div>';
}
$html .= '
</div>
</div>';
} else {
$html .= '
<div class="collection-single-item">
<div class="item-info">
<div class="item-title"><a href="' . htmlspecialchars($item['link']) . '" target="_blank">' . htmlspecialchars($item['title']) . '</a></div>';
if ($showExcerpt && isset($item['excerpt']) && $item['excerpt']) {
$html .= '<p class="item-excerpt">' . htmlspecialchars($item['excerpt']) . '</p>';
}
if ($showDate && isset($item['created']) && $item['created']) {
$date = date('Y-m-d', $item['created']);
$html .= '<div class="item-date">发布于 ' . $date . '</div>';
}
$html .= '
</div>
</div>';
}
} else if ($itemsCount > 1) {
$html .= '
<div class="collection-items-container">';
if ($displayMode === 'collapsible') {
// 预览内容最多3个
$previewCount = min(3, $itemsCount);
$previewItems = array_slice($items, 0, $previewCount);
$remainingItems = array_slice($items, $previewCount);
if ($previewCount > 0) {
$html .= '
<div class="items-preview">';
foreach ($previewItems as $item) {
$html .= '
<div class="item-preview-item">';
if ($collectionType === 'comment') {
$authorLink = !empty($item['url']) ?
'<a href="' . htmlspecialchars($item['url']) . '" target="_blank" class="author-link">' . htmlspecialchars($item['author']) . '</a>' :
htmlspecialchars($item['author']);
$html .= '
<div class="item-preview-content">
<a href="' . htmlspecialchars($item['link']) . '" target="_blank" class="comment-link">' . htmlspecialchars(self::getExcerpt($item['content'], 60)) . '</a>
</div>
<div class="comment-preview-meta">
<div class="comment-preview-author">
<strong>' . $authorLink . '</strong>
</div>';
if ($showDate && isset($item['created']) && $item['created']) {
$date = date('Y-m-d', $item['created']);
$html .= '<div class="comment-preview-date">' . $date . '</div>';
}
$html .= '
</div>';
} elseif ($collectionType === 'user') {
$userNameLink = !empty($item['url']) ?
'<a href="' . htmlspecialchars($item['url']) . '" target="_blank" class="user-link">' . htmlspecialchars($item['name']) . '</a>' :
htmlspecialchars($item['name']);
$html .= '
<div class="item-preview-name">
<strong>' . $userNameLink . '</strong>
</div>';
if ($showDate && isset($item['created']) && $item['created']) {
$date = date('Y-m-d', $item['created']);
$html .= '<div class="item-preview-date">注册于 ' . $date . '</div>';
}
if ($collectionType === 'user' && isset($item['recentActivity']) && $item['recentActivity']) {
$html .= '<div class="item-preview-activity">最近活跃:' . $item['recentActivity'] . '</div>';
}
} else {
$html .= '
<div class="item-preview-title">
<a href="' . htmlspecialchars($item['link']) . '" target="_blank">' . htmlspecialchars($item['title']) . '</a>
</div>';
if ($showDate && isset($item['created']) && $item['created']) {
$date = date('Y-m-d', $item['created']);
$html .= '<div class="item-preview-date">发布于 ' . $date . '</div>';
}
}
$html .= '</div>';
}
$html .= '
</div>';
}
// 如果有剩余内容,显示展开按钮和剩余内容列表
if (count($remainingItems) > 0) {
$html .= '
<div class="collection-toggle-container">
<button type="button" class="collection-toggle-btn" data-target="' . $collectionCardId . '">
<span class="toggle-text">展开查看更多' . ($collectionType === 'comment' ? '评论' : ($collectionType === 'user' ? '用户' : '文章')) . '' . count($remainingItems) . '个)</span>
<span class="toggle-icon"></span>
</button>
</div>';
$html .= '
<div class="collection-items-full" style="display: none;">
<div class="items-list">';
// 只显示剩余的内容,不重复显示预览中的内容
foreach ($remainingItems as $item) {
$html .= '
<div class="item-list-item">';
if ($collectionType === 'comment') {
$authorLink = !empty($item['url']) ?
'<a href="' . htmlspecialchars($item['url']) . '" target="_blank" class="author-link">' . htmlspecialchars($item['author']) . '</a>' :
htmlspecialchars($item['author']);
$html .= '
<div class="item-list-content">
<a href="' . htmlspecialchars($item['link']) . '" target="_blank" class="comment-link">' . htmlspecialchars(self::getExcerpt($item['content'], 100)) . '</a>
</div>
<div class="item-list-info">
<div class="item-list-author">
<strong>' . $authorLink . '</strong>
</div>
<div class="item-list-date">' . date('Y-m-d', $item['created']) . '</div>
</div>';
} elseif ($collectionType === 'user') {
$userNameLink = !empty($item['url']) ?
'<a href="' . htmlspecialchars($item['url']) . '" target="_blank" class="user-link">' . htmlspecialchars($item['name']) . '</a>' :
htmlspecialchars($item['name']);
$html .= '
<div class="item-list-info">
<div class="item-list-name">
<strong>' . $userNameLink . '</strong>
</div>
<div class="item-list-date">' . date('Y-m-d', $item['created']) . '</div>
</div>';
if (isset($item['recentActivity']) && $item['recentActivity']) {
$html .= '<div class="item-list-activity">最近活跃:' . $item['recentActivity'] . '</div>';
}
} else {
$html .= '
<div class="item-list-info">
<div class="item-list-title">
<a href="' . htmlspecialchars($item['link']) . '" target="_blank">' . htmlspecialchars($item['title']) . '</a>
</div>
<div class="item-list-date">' . date('Y-m-d', $item['created']) . '</div>
</div>';
if ($showExcerpt && isset($item['excerpt']) && $item['excerpt']) {
$html .= '<div class="item-list-excerpt">' . htmlspecialchars($item['excerpt']) . '</div>';
}
}
$html .= '</div>';
}
$html .= '
</div>
</div>';
}
} else {
// 始终展开模式
$html .= '
<div class="items-list always-expanded">';
foreach ($items as $item) {
$html .= '
<div class="item-list-item">';
if ($collectionType === 'comment') {
$authorLink = !empty($item['url']) ?
'<a href="' . htmlspecialchars($item['url']) . '" target="_blank" class="author-link">' . htmlspecialchars($item['author']) . '</a>' :
htmlspecialchars($item['author']);
$html .= '
<div class="item-list-content">
<a href="' . htmlspecialchars($item['link']) . '" target="_blank" class="comment-link">' . htmlspecialchars(self::getExcerpt($item['content'], 100)) . '</a>
</div>
<div class="item-list-info">
<div class="item-list-author">
<strong>' . $authorLink . '</strong>
</div>
<div class="item-list-date">' . date('Y-m-d', $item['created']) . '</div>
</div>';
} elseif ($collectionType === 'user') {
$userNameLink = !empty($item['url']) ?
'<a href="' . htmlspecialchars($item['url']) . '" target="_blank" class="user-link">' . htmlspecialchars($item['name']) . '</a>' :
htmlspecialchars($item['name']);
$html .= '
<div class="item-list-info">
<div class="item-list-name">
<strong>' . $userNameLink . '</strong>
</div>
<div class="item-list-date">' . date('Y-m-d', $item['created']) . '</div>
</div>';
if (isset($item['recentActivity']) && $item['recentActivity']) {
$html .= '<div class="item-list-activity">最近活跃:' . $item['recentActivity'] . '</div>';
}
} else {
$html .= '
<div class="item-list-info">
<div class="item-list-title">
<a href="' . htmlspecialchars($item['link']) . '" target="_blank">' . htmlspecialchars($item['title']) . '</a>
</div>
<div class="item-list-date">' . date('Y-m-d', $item['created']) . '</div>
</div>';
if ($showExcerpt && isset($item['excerpt']) && $item['excerpt']) {
$html .= '<div class="item-list-excerpt">' . htmlspecialchars($item['excerpt']) . '</div>';
}
}
$html .= '</div>';
}
$html .= '
</div>';
}
$html .= '
</div>';
} else {
$html .= '
<div class="collection-no-items">
<p>该合集暂无关联' . ($collectionType === 'comment' ? '评论' : ($collectionType === 'user' ? '用户' : '文章')) . '</p>
</div>';
}
$html .= '
</div>';
$config = array(
'containerId' => $collectionCardId,
'collectionId' => $collectionId,
'name' => $collection['name'],
'type' => $collectionType
);
return array($html, self::getCollectionStyles(), $config);
}
/**
* 移除header方法改为在解析短代码时内联CSS
*/
public static function header()
{
// 不再使用header方法输出CSS
}
/**
* 输出JS到页面底部
*/
public static function footer()
{
if (!empty(self::$collectionConfigs) && !self::$jsAdded) {
echo self::getCollectionScripts(self::$collectionConfigs);
self::$jsAdded = true;
}
}
/**
* 获取合集CSS样式
*/
private static function getCollectionStyles()
{
return '
.collection-card {
border: 1px solid #e8e8e8;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
background: white;
margin: 20px 0;
padding: 20px;
}
.collection-header {
margin-bottom: 20px;
border-bottom: 1px solid #e8e8e8;
padding-bottom: 15px;
}
.collection-title-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.collection-title {
margin: 0;
font-size: 20px;
font-weight: 600;
color: #333;
flex: 1;
}
.collection-count {
color: #666;
font-size: 14px;
padding: 4px 10px;
background: #f5f5f5;
border-radius: 4px;
white-space: nowrap;
margin-left: 15px;
}
.collection-description {
color: #666;
font-size: 14px;
line-height: 1.6;
}
.collection-single-item {
display: flex;
gap: 20px;
align-items: flex-start;
}
.item-info {
flex: 1;
min-width: 0;
}
.item-title {
margin: 0 0 10px 0;
font-size: 18px;
font-weight: 500;
color: #333;
}
.item-title a {
color: #333;
text-decoration: none;
}
.item-title a:hover {
color: #3b82f6;
text-decoration: underline;
}
.item-name {
margin: 0 0 10px 0;
font-size: 18px;
font-weight: 500;
color: #333;
}
.item-name a.user-link {
color: #333;
text-decoration: none;
}
.item-name a.user-link:hover {
color: #3b82f6;
text-decoration: underline;
}
.comment-meta {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 8px;
color: #999;
font-size: 13px;
}
.comment-author, .comment-date {
color: #999;
font-size: 13px;
}
.comment-author a.author-link {
color: #999;
text-decoration: none;
}
.comment-author a.author-link:hover {
color: #3b82f6;
text-decoration: underline;
}
.item-excerpt {
margin: 10px 0;
color: #666;
font-size: 14px;
line-height: 1.6;
}
.item-date, .item-activity {
color: #999;
font-size: 13px;
margin-top: 5px;
}
.item-content-link a.comment-link {
color: #666;
text-decoration: none;
display: block;
padding: 8px 0;
border-left: none;
padding-left: 0;
}
.item-content-link a.comment-link:hover {
color: #3b82f6;
text-decoration: underline;
}
.collection-items-container {
margin-top: 15px;
}
.items-preview {
margin-bottom: 15px;
}
.item-preview-item {
padding: 10px 0;
border-bottom: 1px dashed #e8e8e8;
}
.item-preview-item:last-child {
border-bottom: none;
}
.item-preview-title a {
color: #333;
text-decoration: none;
font-size: 15px;
}
.item-preview-title a:hover {
color: #3b82f6;
text-decoration: underline;
}
.item-preview-name, .item-preview-author {
font-weight: 500;
margin-bottom: 5px;
color: #333;
}
.item-preview-name a.user-link,
.item-preview-author a.author-link {
color: #333;
text-decoration: none;
}
.item-preview-name a.user-link:hover,
.item-preview-author a.author-link:hover {
color: #3b82f6;
text-decoration: underline;
}
.item-preview-content {
color: #666;
font-size: 13px;
line-height: 1.5;
margin-bottom: 5px;
}
.item-preview-content a.comment-link {
color: #666;
text-decoration: none;
}
.item-preview-content a.comment-link:hover {
color: #3b82f6;
text-decoration: underline;
}
.comment-preview-meta {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 5px;
color: #999;
font-size: 12px;
}
.comment-preview-author, .comment-preview-date {
color: #999;
font-size: 12px;
}
.comment-preview-author a.author-link {
color: #999;
text-decoration: none;
}
.comment-preview-author a.author-link:hover {
color: #3b82f6;
text-decoration: underline;
}
.item-preview-date, .item-preview-activity {
color: #999;
font-size: 12px;
margin-top: 3px;
}
.collection-toggle-container {
text-align: center;
margin: 15px 0;
padding-top: 15px;
border-top: 1px solid #e8e8e8;
}
.collection-toggle-btn {
background: none;
border: 1px solid #ddd;
border-radius: 4px;
padding: 8px 20px;
color: #666;
cursor: pointer;
font-size: 14px;
display: inline-flex;
align-items: center;
gap: 8px;
transition: all 0.3s;
}
.collection-toggle-btn:hover {
background: #f5f5f5;
border-color: #ccc;
}
.collection-toggle-btn.expanded .toggle-icon {
transform: rotate(180deg);
}
.toggle-icon {
transition: transform 0.3s;
font-size: 12px;
}
.collection-items-full {
margin-top: 20px;
}
.items-list {
display: flex;
flex-direction: column;
gap: 15px;
}
.item-list-item {
padding: 15px;
border: 1px solid #e8e8e8;
border-radius: 6px;
background: #f9f9f9;
}
.item-list-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.item-list-title a {
color: #333;
text-decoration: none;
font-size: 16px;
font-weight: 500;
}
.item-list-title a:hover {
color: #3b82f6;
text-decoration: underline;
}
.item-list-name, .item-list-author {
color: #333;
font-size: 16px;
font-weight: 500;
}
.item-list-name a.user-link,
.item-list-author a.author-link {
color: #333;
text-decoration: none;
}
.item-list-name a.user-link:hover,
.item-list-author a.author-link:hover {
color: #3b82f6;
text-decoration: underline;
}
.item-list-date {
color: #999;
font-size: 13px;
flex-shrink: 0;
margin-left: 15px;
}
.item-list-excerpt {
color: #666;
font-size: 14px;
line-height: 1.5;
margin-top: 8px;
}
.item-list-content {
color: #666;
font-size: 14px;
line-height: 1.5;
margin-bottom: 8px;
}
.item-list-content a.comment-link {
color: #666;
text-decoration: none;
display: block;
padding: 8px 0;
border-left: none;
padding-left: 0;
}
.item-list-content a.comment-link:hover {
color: #3b82f6;
text-decoration: underline;
}
.item-list-activity {
margin-top: 5px;
color: #666;
font-size: 13px;
}
.collection-no-items {
text-align: center;
padding: 30px;
color: #999;
font-size: 16px;
background: #f9f9f9;
border-radius: 6px;
}
.collection-error {
padding: 20px;
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
border-radius: 4px;
text-align: center;
}
/* 网格布局 */
.collection-card[data-display-mode="grid"] .items-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 15px;
}
.collection-card[data-display-mode="grid"] .item-list-item {
margin: 0;
}
/* 深色模式适配 */
.dark .collection-card {
background: #1a1a1a;
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.dark .collection-header {
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.dark .collection-title {
color: #fff;
}
.dark .collection-count {
background: #2a2a2a;
color: #ccc;
}
.dark .collection-description {
color: #ccc;
}
.dark .item-title a,
.dark .item-preview-title a,
.dark .item-list-title a {
color: #999;
text-decoration: none;
}
.dark .item-title a:hover,
.dark .item-preview-title a:hover,
.dark .item-list-title a:hover {
color: #3b82f6;
text-decoration: underline;
}
.dark .item-name,
.dark .item-author,
.dark .item-list-name,
.dark .item-list-author,
.dark .item-preview-name,
.dark .item-preview-author {
color: #ddd;
}
.dark .item-name a.user-link,
.dark .item-author a.author-link,
.dark .item-list-name a.user-link,
.dark .item-list-author a.author-link,
.dark .item-preview-name a.user-link,
.dark .item-preview-author a.author-link {
color: #ddd;
}
.dark .item-name a.user-link:hover,
.dark .item-author a.author-link:hover,
.dark .item-list-name a.user-link:hover,
.dark .item-list-author a.author-link:hover,
.dark .item-preview-name a.user-link:hover,
.dark .item-preview-author a.author-link:hover {
color: #3b82f6;
}
.dark .comment-meta,
.dark .comment-author,
.dark .comment-date,
.dark .comment-preview-meta,
.dark .comment-preview-author,
.dark .comment-preview-date {
color: #999;
}
.dark .comment-author a.author-link,
.dark .comment-preview-author a.author-link {
color: #999;
}
.dark .comment-author a.author-link:hover,
.dark .comment-preview-author a.author-link:hover {
color: #3b82f6;
}
.dark .item-excerpt,
.dark .item-list-excerpt,
.dark .item-list-content,
.dark .item-preview-content {
color: #ccc;
}
.dark .item-content-link a.comment-link,
.dark .item-list-content a.comment-link,
.dark .item-preview-content a.comment-link {
color: #ccc;
border-left: none;
}
.dark .item-content-link a.comment-link:hover,
.dark .item-list-content a.comment-link:hover,
.dark .item-preview-content a.comment-link:hover {
color: #3b82f6;
}
.dark .collection-toggle-container,
.dark .item-preview-item {
border-top-color: rgba(255, 255, 255, 0.1);
border-bottom-color: rgba(255, 255, 255, 0.1);
}
.dark .item-list-item {
background: #2a2a2a;
border-color: rgba(255, 255, 255, 0.1);
}
.dark .item-list-date,
.dark .item-preview-date,
.dark .item-date,
.dark .item-activity {
color: #999;
}
.dark .collection-toggle-btn {
border-color: rgba(255, 255, 255, 0.2);
color: #ccc;
}
.dark .collection-toggle-btn:hover {
background: rgba(255, 255, 255, 0.1);
border-color: rgba(255, 255, 255, 0.3);
}
.dark .collection-no-items {
background: #2a2a2a;
color: #ccc;
}
/* 响应式设计 */
@media (max-width: 768px) {
.collection-single-item {
flex-direction: column;
}
.collection-title-row {
flex-direction: column;
align-items: flex-start;
}
.collection-count {
margin-left: 0;
margin-top: 5px;
}
.collection-card[data-display-mode="grid"] .items-list {
grid-template-columns: 1fr;
}
.item-list-info {
flex-direction: column;
align-items: flex-start;
}
.item-list-date {
margin-left: 0;
margin-top: 5px;
}
.comment-meta,
.comment-preview-meta {
flex-direction: column;
align-items: flex-start;
gap: 3px;
}
}
@media (max-width: 480px) {
.collection-card {
padding: 15px;
}
}
';
}
/**
* 获取合集JS脚本
*/
private static function getCollectionScripts($collectionConfigs)
{
$configsJson = json_encode($collectionConfigs);
return '
<script>
(function() {
function initCollection() {
// 处理可折叠合集的展开/收起功能
document.querySelectorAll(".collection-toggle-btn").forEach(function(button) {
button.addEventListener("click", function() {
var targetId = this.getAttribute("data-target");
var targetCard = document.getElementById(targetId);
var fullContent = targetCard.querySelector(".collection-items-full");
var toggleText = this.querySelector(".toggle-text");
var toggleIcon = this.querySelector(".toggle-icon");
if (fullContent.style.display === "none") {
fullContent.style.display = "block";
toggleText.textContent = "收起剩余内容";
this.classList.add("expanded");
toggleIcon.style.transform = "rotate(180deg)";
} else {
fullContent.style.display = "none";
// 更新按钮文本显示剩余内容数量
var remainingCount = fullContent.querySelectorAll(".item-list-item").length;
var collectionType = targetCard.getAttribute("data-collection-type");
var typeText = collectionType === "comment" ? "评论" :
collectionType === "user" ? "用户" : "文章";
toggleText.textContent = "展开查看更多" + typeText + "" + remainingCount + "个)";
button.classList.remove("expanded");
toggleIcon.style.transform = "";
}
});
});
// 网格布局的特殊处理
document.querySelectorAll(".collection-card[data-display-mode=\'grid\']").forEach(function(card) {
var items = card.querySelectorAll(".item-list-item");
if (items.length > 0) {
items.forEach(function(item) {
item.addEventListener("mouseenter", function() {
this.style.transform = "translateY(-2px)";
this.style.boxShadow = "0 4px 12px rgba(0,0,0,0.15)";
});
item.addEventListener("mouseleave", function() {
this.style.transform = "";
this.style.boxShadow = "";
});
});
}
});
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initCollection);
} else {
setTimeout(initCollection, 100);
}
})();
</script>';
}
/**
* 同步关联内容
*/
private static function syncRelatedItems($collectionId, $itemId, $itemType = 'article')
{
try {
$db = self::getDbConnection();
$stmt = $db->prepare("SELECT related_items, collection_type FROM plugin_collection WHERE id = ?");
$stmt->execute(array($collectionId));
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if ($result) {
// 检查合集类型是否匹配
if ($result['collection_type'] != $itemType) {
return false;
}
$currentRelatedItems = $result['related_items'];
$relatedItemsArray = array();
if (!empty($currentRelatedItems)) {
$relatedItemsArray = explode(',', $currentRelatedItems);
$relatedItemsArray = array_map('trim', $relatedItemsArray);
$relatedItemsArray = array_filter($relatedItemsArray);
}
if (!in_array($itemId, $relatedItemsArray)) {
$relatedItemsArray[] = $itemId;
$newRelatedItems = implode(',', $relatedItemsArray);
$updateStmt = $db->prepare("UPDATE plugin_collection SET related_items = ? WHERE id = ?");
$updateStmt->execute(array($newRelatedItems, $collectionId));
return true;
}
}
} catch (Exception $e) {
error_log('Collection: 同步关联内容失败: ' . $e->getMessage());
}
return false;
}
/**
* 文章保存时的处理
*/
public static function onPostSave($content)
{
$cid = isset($content['cid']) ? $content['cid'] : 0;
if ($cid && isset($content['text'])) {
$pattern = '/\{collection-(\d+)\}/i';
if (preg_match_all($pattern, $content['text'], $matches)) {
foreach ($matches[1] as $collectionId) {
$collection = self::getCollectionById($collectionId);
if ($collection) {
self::syncRelatedItems($collectionId, $cid, 'article');
}
}
}
}
return $content;
}
/**
* 文章写入时的处理
*/
public static function onPostWrite($content)
{
return self::onPostSave($content);
}
/**
* 获取关联文章信息
*/
public static function getRelatedArticlesInfo($relatedArticles)
{
$result = array();
if (empty($relatedArticles)) {
return $result;
}
$articleIds = explode(',', $relatedArticles);
$articleIds = array_map('trim', $articleIds);
$articleIds = array_filter($articleIds);
foreach ($articleIds as $cid) {
if (is_numeric($cid)) {
$articleInfo = self::getArticleInfo($cid);
if ($articleInfo['title']) {
$result[$cid] = array(
'title' => $articleInfo['title'],
'link' => $articleInfo['link'],
'cid' => $cid
);
}
}
}
return $result;
}
/**
* 获取关联评论信息
*/
public static function getRelatedCommentsInfo($relatedComments)
{
$result = array();
if (empty($relatedComments)) {
return $result;
}
$commentIds = explode(',', $relatedComments);
$commentIds = array_map('trim', $commentIds);
$commentIds = array_filter($commentIds);
foreach ($commentIds as $coid) {
if (is_numeric($coid)) {
$commentInfo = self::getCommentInfo($coid);
if ($commentInfo['author']) {
$result[$coid] = array(
'author' => $commentInfo['author'],
'content' => $commentInfo['text'],
'coid' => $coid,
'link' => $commentInfo['link'],
'url' => $commentInfo['url']
);
}
}
}
return $result;
}
/**
* 获取关联用户信息
*/
public static function getRelatedUsersInfo($relatedUsers)
{
$result = array();
if (empty($relatedUsers)) {
return $result;
}
$userIds = explode(',', $relatedUsers);
$userIds = array_map('trim', $userIds);
$userIds = array_filter($userIds);
foreach ($userIds as $uid) {
if (is_numeric($uid)) {
$userInfo = self::getUserInfo($uid);
if ($userInfo['name']) {
$result[$uid] = array(
'name' => $userInfo['name'],
'url' => $userInfo['url'],
'uid' => $uid,
'commentCount' => $userInfo['commentCount'],
'recentActivity' => $userInfo['recentActivity']
);
}
}
}
return $result;
}
}
?>