# YouQuan **Repository Path**: xiguacaizimi/YouQuan ## Basic Information - **Project Name**: YouQuan - **Description**: Typecho 有圈插件:聚合友链 RSS 的「博友圈」页面,适配 ilogs 主题与 FriendLinks 友链插件,兼容 Typecho 1.1 / 1.2 / 1.3 - **Primary Language**: PHP - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-10-31 - **Last Updated**: 2026-10-31 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 有圈 YouQuan > 给 Typecho + ilogs 主题做的「博友圈」插件:把友链的 RSS 聚合成一个时间线页面。 > > 后台可管理每条友链的订阅地址与抓到的文章;可与 **FriendLinks 友链插件**打通,友链里填的 RSS 地址支持**一键导入**并立即抓取。 > > **页面自带导航图标,且不需要在页面里写任何短代码** —— 插件会接管该独立页面的渲染,外层直接用主题的页头 / 左栏 / 导航 / 页脚。 - 插件名:有圈(目录名必须是 `YouQuan`) - 版本:1.2.1 - 适用:Typecho 1.1 / 1.2 / **1.3** - 建议搭配:ilogs 主题、FriendLinks 友链插件 - 作者:xiguacaizimi  ·  https://www.xiguacaizimi.top  ·  xiguacaizimi@163.com --- ## 一、安装 1. 解压后确认目录名是 **`YouQuan`**(大小写敏感,Linux 主机上写成 `youquan` 会失效)。 2. 把整个 `YouQuan` 目录上传到站点的 `usr/plugins/` 下,最终结构应为: ``` usr/plugins/YouQuan/ ├─ Plugin.php 插件入口:钩子注册、短代码、短链接、页面接管、插件设置页 ├─ Manage.php 后台管理面板(四个标签页,Typecho 原生风格) ├─ Feed.php 数据层:建表 / 抓取 / RSS 解析 / 建页面与图标 ├─ Render.php 前台渲染层(含页面接管渲染) ├─ Config.php 配置读写(独立 KV 表) ├─ templates/ │ └─ page.php 页面接管模板:复用 ilogs 的 template-parts 外壳 └─ assets/ ├─ front.css 前台样式(与 ilogs 相册页视觉对齐) ├─ admin.css 后台样式(Typecho 原生色板) └─ admin.js 后台交互(导入、抓取、自动发现 RSS) ``` 3. 进入 **控制台 → 插件**,启用「有圈」。启用时会自动: - 建三张表; - **创建「博友圈」页面**,并写入导航图标字段; - 注册后台菜单 **控制台 → 有圈**。 | 表名 | 说明 | | --- | --- | | `youquan_options` | 插件配置(KV),不占用 Typecho 插件配置的序列化结构 | | `youquan_feeds` | 圈友 / 订阅源(含 RSS 地址、头像、抓取状态、ETag 等) | | `youquan_posts` | 抓取到的文章(按 `fid + guid` 唯一,天然去重) | 4. 装完直接访问 `/youquan`,或点 ilogs 左栏里那个带图标的「博友圈」即可。 > 停用插件只会移除后台菜单,**三张表的数据全部保留**,重新启用即可继续使用。 --- ## 二、快速上手(三步出效果) 1. **导入圈友**:控制台 → 有圈 →「圈友」→ 右上角 **从友链导入**,勾选要订阅的友链后导入(会自动抓取)。 没装 FriendLinks 也可以点 **添加圈友** 手动填写订阅地址。 2. **确认页面**:控制台 → 有圈 →「设置」→「页面与入口」。启用时页面通常已自动建好; 若你删过页面或换过主题,点 **修复页面与图标** 一次即可重建并补齐导航图标。 3. **看效果**:访问 `https://你的域名/youquan`,或直接在 ilogs 左栏导航里点「博友圈」。 --- ## 三、免短代码是怎么做到的 这是本插件与常见 RSS 聚合插件最大的区别,做法与 ilogs 生态里的图库插件一致: 1. **建一个承载页面**。插件创建一个别名为 `youquan` 的独立页面,并给它写入三个自定义字段: | 字段 | 值 | 作用 | | --- | --- | --- | | `youquanHost` | `1` | 标记这是有圈的页面,供插件查找 / 重建 | | `showPage` | `1` | 让页面出现在 ilogs 的左栏与导航里 | | `iconPage` | 24×24 Tabler `users` SVG | 导航里显示的图标 | > `showPage` / `iconPage` 只在**为空时**写入,你在主题里改过的图标不会被覆盖。 2. **在渲染前接管**。插件注册 Typecho 的 `Widget\Archive` → `beforeRender` 钩子 (同时兼容 1.1 的 `Widget_Archive` 写法)。Typecho 在 `require 主题模板` 之前会调用它, 插件判断当前页面是不是有圈页面,是就走 `templates/page.php`。 3. **复用主题外壳**。`templates/page.php` 直接引入主题自己的片段: ``` template-parts/header.php template-parts/left.php (单栏布局时跳过)
template-parts/nav-menu.php
← 博友圈 template-parts/right.php (单栏布局时跳过) template-parts/footer-copyright.php template-parts/footer.php ``` 所以左栏、导航、右栏、页脚跟主题的其它页面完全一致,不会多出主题的空正文区域。 **每个片段都先判断文件是否存在**,主题缺哪个就跳过哪个; 主题本身没有 `template-parts/` 结构时,插件直接返回,交回主题正常渲染(此时用短代码兜底)。 4. **短代码仍然是兜底**。页面正文里依然留着 `[youquan]`,万一主题不支持接管(非 ilogs), 把短代码删掉换成主题自己的模板标签即可,不会白屏。 --- ## 四、前台四种调用方式 插件同时支持四种方式,**任选其一**即可,互不冲突。 ### 1. 独立页面(推荐) 到「设置 → 页面与入口」点「创建并绑定「有圈」页面」,页面上什么都不用写。 启用插件时会自动建好,导航里也会出现带图标的入口。 ### 2. 短代码 想在别的页面中间插入博友圈,正文放: ``` [youquan] ``` 带参数: ``` [youquan layout="grid" per_page="6" title="博友圈" filter="0"] ``` 会自动处理 Markdown 把短代码包成 `

[youquan]

` 的情况,不会显示成代码块。 ### 3. 主题模板标签 在主题模板(如 `page.php`、自定义页面模板)里直接写: ```php 'grid', 'per_page' => 6)); ?> ``` 取短链接地址: ```php 博友圈 ``` ### 4. 短链接 `/youquan` 插件通过 `index.php` 的 `begin` 钩子拦截 `/youquan`,302 跳转到绑定好的有圈页面。 - 后缀可在「设置 → 页面与入口 → 页面别名」里改,改成 `friends` 就访问 `/friends`。 - **为什么不用 `Helper::addRoute()`**:`addRoute` 会把路由写进 `options.routingTable` 这个序列化数组,插件卸载残留会导致整站 404。本插件改用 `begin` 钩子拦截,完全不碰路由表。 - 尚未创建页面时:管理员访问 `/youquan` 会**自动建页面**,普通访客会看到一个引导到后台的提示页,不会白屏。 ### 可用参数 | 参数 | 可选值 | 默认 | 说明 | | --- | --- | --- | --- | | `per_page` / `limit` | 正整数 | 12 | 每页条数 | | `layout` | `list` / `grid` | list | 列表流 / 卡片流 | | `title` | 字符串 | 博友圈 | 标题;`title=""` 隐藏标题栏文字 | | `head` | `0` / `1` | 1 | 是否显示标题栏(含圈友数与文章数) | | `filter` | `0` / `1` | 1 | 是否显示圈友筛选条 | | `src` | 圈子 ID | 全部 | 只显示某个圈友的文章 | | `order` | `published` / `created` | published | 排序方式 | --- ## 五、后台 后台面板(**控制台 → 有圈**)完全按 Typecho 原生风格排版: `typecho-page-title` 标题栏 + `typecho-option-tabs` 标签页 + 卡片表单 + 表格, 配色沿用 Typecho 的 `#467B96` 主色、`#E9E9E6` 按钮底、`#D9D9D6` 边框,与控制台其它页面一致。 ### 圈友 - 表格字段:头像、名称、站点、订阅地址、状态徽章、最近抓取时间、文章数、排序。 - 每行支持 **编辑 / 抓取 / 停用启用 / 删除**;支持勾选后批量停用、启用、删除。 - 状态徽章:`成功`(绿)/ `失败`(红,悬停看错误原因)/ `待抓取`(灰)/ `已停用`(灰)。 - 编辑弹窗里填了站点地址后点 **自动发现**,会自动探测常见 RSS 地址(`/feed`、`/rss.xml`、`/atom.xml`、`/index.xml`、`?feed=rss2` 等),无需手填。 - 工具区: - **清理重复**:按归一化后的文章链接分组,删除重复项,只保留最早抓到的那条。 - **补全头像**:给没有头像的圈友批量补站点 favicon(每次最多 30 个)。 ### 文章 - 汇总所有圈友抓来的文章,支持按**来源圈友**与**关键词**筛选,支持隐藏/显示、删除。 - 不想要某篇文章时用「隐藏」而不是「删除」,否则下次抓取还会再抓回来。 - 「清空文章」只清已抓的文章(订阅保留),重新抓取即可重建。 ### 设置 1. **展示设置**:标题、副标题、每页条数、布局(列表/卡片)、摘要字数、是否显示头像 / 来源 / 时间 / 封面 / 筛选条 / 标题栏、时间格式(相对时间 or 日期)、排序、新窗口打开、**隐藏页面标题**(避免页面上出现两个标题)。 2. **页面与入口**:选择要绑定的页面、页面别名(决定短链接)、创建 / 重新绑定有圈页面、**修复页面与图标**(重建页面并补齐 `showPage` / `iconPage`)。 3. **抓取设置**:自动刷新开关与间隔(分钟,默认 30)、超时秒数(默认 8)、**每个圈友保留条数**(默认 20,超出自动裁剪旧文章以控制数据库体积)、排除关键词(逗号分隔,命中则不入库)。 ### 调用方式 内置四种调用方式的完整示例、参数表、与 FriendLinks 的配合说明以及常见问题,可直接复制使用。 --- ## 六、插件设置页(控制台 → 插件 → 有圈 → 设置) 除了上述管理面板,插件还在 Typecho 的插件列表里提供了原生设置页,放最常改的 8 项: | 设置项 | 说明 | | --- | --- | | 页面大标题 | 前台标题栏大字,说明里带管理面板入口与当前统计 | | 标题下的说明文字 | 副标题,留空则不显示 | | 短链接别名 | 决定 `/youquan` 这个短链接 | | 前台布局 | 列表流 / 卡片流 | | 每页文章数 | 1 – 50 | | 自动刷新 | 访客打开页面时顺带抓取过期订阅 | | 刷新间隔(分钟) | 最低 5 | | 每个圈友保留条数 | 最高 200,超出自动裁剪 | 保存时会被安全夹取:每页条数上限 50、间隔下限 5、保留条数上限 200、别名只保留字母数字下划线连字符。 > 设置值写入 `youquan_options`,与管理面板共用同一份数据,两处改动都不会冲突,且会互相同步。 > > 这是通过定义 `configHandle()` 实现的:Typecho 检测到该方法后不会再往 `options.plugins` 里写序列化配置。 > 但 Typecho 渲染设置页时仍会读取 `options` 表里的 `plugin:YouQuan` 行,读不到会直接 500, > 所以插件会自己维护这一行:启用时创建,之后每次保存设置时**整体覆盖**(不是合并)。 > 从旧版本升级时,那一行里残留的废弃键会被一并清掉。 --- ## 七、与 FriendLinks 友链插件的配合 这是本插件主要的数据来源,已做深度适配: 1. **直接读表**:读取 `{prefix}friend_links`(字段 `linkid / nickname / websiteurl / rssurl / avatar / email / email_md5 / personalintro / rssStatus`),无需 FriendLinks 提供接口。未安装时「从友链导入」会提示未检测到友链数据,其余功能不受影响。 2. **一键导入**:弹窗列出所有友链,勾选后导入。RSS 状态为「禁用」的友链会标灰。 3. **RSS 缺失自动补齐**:友链没填 RSS 地址时,导入时会自动到站点首页探测常见 Feed 地址,并在列表里标注「已发现」。 4. **去重**:同一 RSS 地址不会重复导入,已导入的友链标记为「已导入」并禁用勾选。 判断时会把 URL 归一化 —— 忽略 http/https、`www.`、结尾斜杠、`/index.php`、重复斜杠,并把 query 转小写, 所以 `http://www.a.com/feed/` 与 `https://a.com/index.php/feed` 会被视为同一个源。 5. **头像复用**:优先 FriendLinks 上传的头像 → 邮箱 MD5 走 FriendLinks 配置的头像服务 → FriendLinks 的 favicon 缓存。都取不到时回退站点 favicon,最后用站点名首字生成纯色头像。 6. **导入即抓取**:导入完成后自动逐个抓取(最多 5 个),剩下的在圈友页点「全部抓取」。 > 之后在 FriendLinks 里新增友链,回到有圈再导一次即可,「已导入」的不会重复。 --- ## 八、支持的 Feed 格式 - RSS 2.0、RSS 1.0(RDF)、Atom 1.0 - 自动识别 `content:encoded` / `description` / `summary` 作为摘要,`dc:creator` / `author` 作为作者 - 封面提取顺序:`media:content` / `media:thumbnail` / `enclosure` → 正文首张 ``;相对地址会自动补成绝对地址 - 自动处理 GBK / GB18030 编码、BOM、以及 XML 里的非法控制字符 - 支持条件请求(`If-None-Match` / `If-Modified-Since`),源站没更新时返回 304,不重复写库 - 抓取优先使用 cURL,缺失时自动降级到 `stream`;限制协议为 http/https,响应体上限 3MB --- ## 九、主题样式适配(ilogs) 前台元素全部写在 `.yq-wrap` 作用域内,并对 ilogs 的既有规则做了必要重置,确保视觉一致: - 直接使用主题的 CSS 变量:`--bs-body-color`、`--bs-border-color-translucent`、`--bs-tertiary-bg`、`--primary-color-rgba`,跟随主题明暗色切换。 - 抵消 ilogs `#post-content a` 的高亮下划线与阴影、`#post-content h1/h2/h3` 的内阴影底色(有圈标题改用 `div[role=heading]`,从根上避让)、`#post-content img` 的 `display:block / height:auto`(头像与封面尺寸需要精确控制)。 - 「隐藏页面标题」开启时,会隐藏主题独立页面的 `#articleTitle` 及其下方描述文字(选择器为 `#post-article #articleTitle`),避免页面上出现两个标题。 - **页头对齐相册页**:标题 `1.75rem / 300` 字重,副标题 13px,右侧 12px 统计文字,底部 1px 分隔线,外框内边距 `34px 32px 48px`,与 ilogs 相册页的 `.album-page-heading` 完全一致。 - 布局与 ilogs 文章列表一致:圆形来源头像 + 标题 + 两行摘要 +「站点 · 时间」元信息 + 右侧缩略图(112×72)。 - 摘要与标题重复时自动省略(去标点后比较;摘要以标题开头则去掉标题前缀)。 - 筛选条会过滤掉 0 篇文章的圈友,最多显示 8 个。 - 响应式:991.98px 以下封面缩小、shell 内边距收到 `24px 20px 36px`;767.98px 以下隐藏封面、内边距收到 `18px 14px 30px`;390px 宽度下无横向溢出。 --- ## 十、常见问题 **Q:访问 `/youquan` 404 或提示页面不存在?** A:到「设置 → 页面与入口」点「创建并绑定「有圈」页面」。若仍未生效,可能是伪静态规则没排除该路径,可在 `.htaccess` / nginx 配置里检查 rewrite 规则。 **Q:左栏导航里有页面但没图标?** A:到「设置 → 页面与入口」点「修复页面与图标」。若你手动改过 `iconPage` 字段,插件不会覆盖,需要自己补 SVG。 **Q:页面能打开,但完全没有样式(头像变大、筛选挤成一堆)?** A:这是 1.1.0 及更早版本的已知问题,1.2.0 已修复(原因见「变更记录」)。 确认一下浏览器里页面源码有没有 `