Files
Collection/Plugin.php
2026-02-23 17:19:04 +08:00

2029 lines
71 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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;
}
}
?>