diff --git a/Plugin.php b/Plugin.php new file mode 100644 index 0000000..a3aca4c --- /dev/null +++ b/Plugin.php @@ -0,0 +1,1471 @@ +getPrefix(); + + $sql = "CREATE TABLE IF NOT EXISTS `{$prefix}thoughts` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `cid` int(10) unsigned NOT NULL COMMENT '文章ID', + `authorId` int(10) unsigned NOT NULL COMMENT '用户ID', + `created` int(10) unsigned DEFAULT 0 COMMENT '创建时间', + `text` text COMMENT '感想内容', + `status` varchar(16) DEFAULT 'approved' COMMENT '状态', + PRIMARY KEY (`id`), + KEY `cid` (`cid`), + KEY `authorId` (`authorId`), + KEY `created` (`created`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"; + + try { + $db->query($sql); + } catch (Exception $e) { + throw new Typecho_Plugin_Exception('创建感想表失败: ' . $e->getMessage()); + } + + // 挂载hook + Typecho_Plugin::factory('Widget_Feedback')->comment = array(__CLASS__, 'processComment'); + Typecho_Plugin::factory('Widget_Archive')->footer = array(__CLASS__, 'footer'); + Typecho_Plugin::factory('Widget_Archive')->header = array(__CLASS__, 'header'); + Typecho_Plugin::factory('Widget_Feedback')->content = array(__CLASS__, 'renderCheckbox'); + + return _t('感想插件已激活,请进行配置'); + } + + /** + * 禁用插件方法 + */ + public static function deactivate() + { + return _t('感想插件已禁用'); + } + + /** + * 插件配置方法 + */ + public static function config(Typecho_Widget_Helper_Form $form) + { + $label = new Typecho_Widget_Helper_Form_Element_Text( + 'label_text', + NULL, + '发布为感想', + _t('勾选框标签文字'), + _t('显示在勾选框旁边的文字') + ); + $form->addInput($label->addRule('required', _t('标签文字不能为空'))); + + // 添加前端卡片默认状态设置 + $default_state = new Typecho_Widget_Helper_Form_Element_Radio( + 'default_state', + array( + 'collapsed' => '默认收起', + 'expanded' => '默认展开' + ), + 'collapsed', + _t('感想卡片默认状态'), + _t('选择感想列表在前端的默认显示状态') + ); + $form->addInput($default_state); + + // 独立页面配置 + $page_per_page = new Typecho_Widget_Helper_Form_Element_Text( + 'page_per_page', + NULL, + '20', + _t('独立页面每页显示数量'), + _t('独立页面每页显示的感想数量') + ); + $form->addInput($page_per_page->addRule('isInteger', _t('请输入整数'))); + } + + /** + * 个人用户的配置方法 + */ + public static function personalConfig(Typecho_Widget_Helper_Form $form){} + + /** + * 处理评论提交 - 彻底拦截版 + */ + public static function processComment($comment, $post) + { + $request = Typecho_Request::getInstance(); + + // 检查是否勾选了发布为感想 + if ($request->isPost() && $request->get('thoughts') == '1') { + // 只有管理员可以发布感想 + $user = Typecho_Widget::widget('Widget_User'); + if ($user->hasLogin() && $user->pass('administrator', true)) { + + // 保存到感想表 + $db = Typecho_Db::get(); + $insert = $db->insert('table.thoughts') + ->rows(array( + 'cid' => $comment['cid'], + 'authorId' => $comment['authorId'], + 'created' => $comment['created'], + 'text' => $comment['text'], + 'status' => 'approved' + )); + + $insertId = $db->query($insert); + + // 关键:直接输出结果并终止,完全拦截Typecho的评论处理 + self::outputSuccessResponse($post); + } + } + + return $comment; + } + + /** + * 输出成功响应并终止 + */ + private static function outputSuccessResponse($post) + { + // 清空可能的输出缓冲区 + if (ob_get_level()) { + ob_end_clean(); + } + + // 设置正确的Content-Type + header('Content-Type: text/html; charset=utf-8'); + + // 构建返回URL + $returnUrl = $post->permalink . '#thoughts'; + + // 输出包含JavaScript的简单HTML页面 + echo ' + + + + 发布成功 + + + +

感想发布成功,正在返回文章页面...

+

如果页面没有自动跳转,请点击这里

+ + '; + + // 立即终止执行,防止Typecho继续处理 + exit; + } + + /** + * 在评论表单中渲染勾选框 + */ + public static function renderCheckbox($content, $class) + { + // 只在文章页面且是管理员显示 + if ($class->request->is('post') && self::isAdmin()) { + $options = Helper::options()->plugin('ThoughtsPlugin'); + $labelText = $options->label_text ?: '发布为感想'; + + $checkbox = '
'; + $checkbox .= ''; + $checkbox .= '
'; + + // 插入到评论框之前 + $content = preg_replace('/(]*name="text"[^>]*>)/i', $checkbox . '$1', $content); + } + + return $content; + } + + /** + * 在页面头部添加CSS - 美化版 + */ + public static function header() + { + // 判断是否在独立页面中 + $isThoughtsPage = false; + + if (isset($_GET['thoughts_page']) || + (isset($_SERVER['REQUEST_URI']) && strpos($_SERVER['REQUEST_URI'], 'thoughts') !== false)) { + $isThoughtsPage = true; + } + + // 独立页面CSS - 美化版 + if ($isThoughtsPage) { + echo ''; + } + + // 文章页面的原有样式保持不变,添加展开收起样式(使用更独特的类名) + if (Typecho_Widget::widget('Widget_Archive')->is('single')) { + echo ''; + } + } + + /** + * 在页面底部添加JS和自动渲染感想(改为始终自动插入) + */ + public static function footer() + { + if (!Typecho_Widget::widget('Widget_Archive')->is('single')) { + return; + } + + // 获取感想HTML + $thoughtsHtml = self::renderThoughts(); + + // 如果有感想数据,始终自动插入(不再检查配置) + if ($thoughtsHtml) { + // 由于删除了位置设置,使用默认位置:文章内容之后 + $position = 'after_post'; + + // 获取配置中的默认状态 + $options = Helper::options()->plugin('ThoughtsPlugin'); + $defaultState = isset($options->default_state) ? $options->default_state : 'collapsed'; + $defaultIsExpanded = ($defaultState === 'expanded'); + + $js = ''; + + echo $js; + } + } + + /** + * 获取感想列表(删除数量限制,改为全部显示) + */ + public static function getThoughts($cid = null) + { + if (!$cid) { + $widget = Typecho_Widget::widget('Widget_Archive'); + $cid = $widget->cid; + } + + if (!$cid) return array(); + + $db = Typecho_Db::get(); + + $select = $db->select() + ->from('table.thoughts') + ->where('cid = ?', $cid) + ->where('status = ?', 'approved') + ->order('created', Typecho_Db::SORT_DESC); + // 删除limit限制,改为全部显示 + + return $db->fetchAll($select); + } + + /** + * 显示感想列表的HTML(有数据才显示) + */ + public static function renderThoughts($cid = null) + { + if (!$cid) { + $widget = Typecho_Widget::widget('Widget_Archive'); + $cid = $widget->cid; + } + + if (!$cid) return ''; + + // 获取感想数据(全部显示) + $thoughts = self::getThoughts($cid); + + // 如果没有感想数据,返回空字符串(不显示任何内容) + if (empty($thoughts)) { + return ''; + } + + // 获取感想条数 + $thoughtsCount = count($thoughts); + + $db = Typecho_Db::get(); + + // 构建正确的HTML结构 + $html = '
'; + $html .= '
'; + $html .= '

回读感想' . $thoughtsCount . '条

'; + $html .= '
'; + + $html .= ''; + $html .= '
'; + + return $html; + } + + /** + * 获取所有感想(用于独立页面) + */ + public static function getAllThoughts($limit = 20, $offset = 0) + { + $db = Typecho_Db::get(); + + $select = $db->select() + ->from('table.thoughts') + ->where('status = ?', 'approved') + ->order('created', Typecho_Db::SORT_DESC); + + // 应用分页限制 + if ($limit > 0) { + $select->limit($limit); + } + + if ($offset > 0) { + $select->offset($offset); + } + + return $db->fetchAll($select); + } + + /** + * 获取感想总数 + */ + public static function getTotalThoughtsCount() + { + $db = Typecho_Db::get(); + $select = $db->select('COUNT(*) as count') + ->from('table.thoughts') + ->where('status = ?', 'approved'); + + $result = $db->fetchRow($select); + return $result ? intval($result['count']) : 0; + } + + /** + * 获取文章信息(修复链接生成) + */ + public static function getPostInfo($cid) + { + $db = Typecho_Db::get(); + $select = $db->select('title', 'slug', 'type') + ->from('table.contents') + ->where('cid = ?', $cid) + ->where('type = ?', 'post') + ->where('status = ?', 'publish'); + + $result = $db->fetchRow($select); + + if ($result) { + // 正确构建文章URL + $result['url'] = Typecho_Common::url( + Typecho_Router::url('post', $result), + Helper::options()->index + ); + } + + return $result; + } + + /** + * 渲染独立页面内容 - 修复分页404问题(删除文章页感想分页功能) + */ + public static function renderThoughtsPage($page = 1, $perPage = null) + { + if (!$perPage) { + $options = Helper::options()->plugin('ThoughtsPlugin'); + $perPage = $options->page_per_page ? intval($options->page_per_page) : 20; + } + + $page = max(1, intval($page)); + $offset = ($page - 1) * $perPage; + + // 获取感想数据 + $thoughts = self::getAllThoughts($perPage, $offset); + $total = self::getTotalThoughtsCount(); + $totalPages = ceil($total / $perPage); + + // 如果请求的页码超过总页数,显示最后一页 + if ($page > $totalPages && $totalPages > 0) { + $page = $totalPages; + $offset = ($page - 1) * $perPage; + $thoughts = self::getAllThoughts($perPage, $offset); + } + + $db = Typecho_Db::get(); + + $html = '
'; + $html .= '
'; + $html .= '

全部感想' . $total . ' 条

'; + + if ($totalPages > 1) { + $html .= '
第 ' . $page . ' 页,共 ' . $totalPages . ' 页
'; + } else { + $html .= '
按时间倒序排列,每次思考都值得被记录
'; + } + + $html .= '
'; + + if (empty($thoughts)) { + $html .= '
+
📝
+

暂时还没有感想记录

+

去文章中发表你的第一个感想吧!

+ 浏览文章 +
'; + } else { + // 显示当前页数据范围 + $startNum = $offset + 1; + $endNum = min($offset + count($thoughts), $total); + + if ($totalPages > 1) { + $html .= '
+ 显示第 ' . $startNum . ' - ' . $endNum . ' 条感想,按时间倒序排列 +
'; + } + + foreach ($thoughts as $index => $thought) { + // 获取用户信息 + $user = $db->fetchRow($db->select() + ->from('table.users') + ->where('uid = ?', $thought['authorId'])); + + // 获取文章信息 + $post = self::getPostInfo($thought['cid']); + + // 优先显示昵称 + if ($user) { + $username = !empty($user['screenName']) ? $user['screenName'] : $user['name']; + } else { + $username = '匿名用户'; + } + + // 文章标题和链接 + if ($post) { + $postTitle = $post['title']; + $postUrl = $post['url']; + } else { + $postTitle = '文章已被删除'; + $postUrl = '#'; + } + + $html .= '
'; + $html .= '
'; + $html .= '' . date('Y年m月d日 H:i', $thought['created']) . ''; + $html .= '' . htmlspecialchars($username) . ''; + $html .= '阅读了《' . htmlspecialchars($postTitle) . ''; + $html .= '
'; + $html .= '
'; + $html .= '发布感想内容为:'; + $html .= nl2br(htmlspecialchars($thought['text'])); + $html .= '
'; + $html .= '
'; + } + + // 分页 - 修复:使用JavaScript处理分页而不是URL参数(保留独立页面分页) + if ($totalPages > 1) { + $html .= '
'; + + // 上一页 + if ($page > 1) { + $html .= '← 上一页'; + } + + // 页码 + $startPage = max(1, $page - 2); + $endPage = min($totalPages, $page + 2); + + // 如果当前页靠近开头,显示更多后面的页码 + if ($startPage == 1) { + $endPage = min($totalPages, $startPage + 4); + } + + // 如果当前页靠近结尾,显示更多前面的页码 + if ($endPage == $totalPages) { + $startPage = max(1, $endPage - 4); + } + + for ($i = $startPage; $i <= $endPage; $i++) { + if ($i == $page) { + $html .= '' . $i . ''; + } else { + $html .= '' . $i . ''; + } + } + + // 下一页 + if ($page < $totalPages) { + $html .= '下一页 →'; + } + + $html .= '
'; + + // 添加JavaScript处理分页 + $html .= ''; + } + } + + $html .= '
'; + return $html; + } + + /** + * 检查当前用户是否为管理员 + */ + public static function isAdmin() + { + $user = Typecho_Widget::widget('Widget_User'); + return $user->hasLogin() && $user->pass('administrator', true); + } + + /** + * 获取感想数量 + */ + public static function getThoughtsCount($cid = null) + { + if (!$cid) { + $widget = Typecho_Widget::widget('Widget_Archive'); + $cid = $widget->cid; + } + + if (!$cid) return 0; + + $db = Typecho_Db::get(); + $select = $db->select('COUNT(*) as count') + ->from('table.thoughts') + ->where('cid = ?', $cid) + ->where('status = ?', 'approved'); + + $result = $db->fetchRow($select); + return $result ? intval($result['count']) : 0; + } +} + +/** + * 助手类,用于模板中调用 + */ +class ThoughtsPlugin +{ + /** + * 显示感想列表(文章页) + */ + public static function showThoughts($cid = null) + { + return ThoughtsPlugin_Plugin::renderThoughts($cid); + } + + /** + * 显示独立页面(全部感想)- 修复分页参数传递 + */ + public static function showThoughtsPage($page = 1, $perPage = null) + { + // 设置标记让CSS生效 + $_GET['thoughts_page'] = true; + + // 优先从URL参数获取页码(解决Typecho路由问题) + if (isset($_GET['page']) && is_numeric($_GET['page'])) { + $page = max(1, intval($_GET['page'])); + } + + return ThoughtsPlugin_Plugin::renderThoughtsPage($page, $perPage); + } + + /** + * 检查是否是管理员 + */ + public static function isAdmin() + { + return ThoughtsPlugin_Plugin::isAdmin(); + } + + /** + * 获取感想数量(单篇文章) + */ + public static function getCount($cid = null) + { + return ThoughtsPlugin_Plugin::getThoughtsCount($cid); + } + + /** + * 获取感想总数(全部) + */ + public static function getTotalCount() + { + return ThoughtsPlugin_Plugin::getTotalThoughtsCount(); + } + + /** + * 获取感想列表数据 + */ + public static function getList($cid = null) + { + // 删除limit参数,改为全部显示 + return ThoughtsPlugin_Plugin::getThoughts($cid); + } +} \ No newline at end of file