Typecho 与 Single-master 主题:代码逻辑详解
读者定位:产品经理 / 非技术背景同学,了解基本网页概念即可阅读。
本文用"产品语言"拆解 Typecho 博客系统和你正在使用的 Single-master 主题的工作原理。
目录
- 前置概念:一个网页是怎么诞生的
- Typecho 核心概念(产品语言版)
- 一次访问的完整生命周期
- Single-master 主题全貌
- 模板渲染:页面是怎么"拼"出来的
- 数据流:数据库的信息怎么跑到页面上
- 前端交互:页面上那些"魔法"怎么实现的
- 关键文件逐个讲解(产品经理版)
- 相册/照片墙:主题与 Album 插件的协作
- 改东西该去哪改?速查表
- 常见术语对照表
1. 前置概念:一个网页是怎么诞生的
在深入代码之前,先建立最简单的心智模型:
"我要看那篇文章"
↓
① 浏览器发请求(URL)
↓
② 服务器接收请求
↓
③ 服务器执行代码
┌─ 从数据库取数据
└─ 把数据填进 HTML 模板
↓
④ 服务器返回 HTML
↓
⑤ 浏览器渲染成你看到的页面
Typecho 就是"②③④"这一层。它用 PHP 这种编程语言来"从数据库取数据,拼成网页"。你网站的主题(Single-master)负责的是步骤 ③ 中最外层的工作——把 Typecho 已经取好的数据,填进一个好看的 HTML 模板里。
类比:Typecho = 餐厅的后厨(采购、切菜、备料),主题 = 摆盘和装饰(怎么把做好的菜漂漂亮亮地端到客人面前)。
2. Typecho 核心概念(产品语言版)
Typecho 是一个用 PHP 写的轻量博客系统。理解以下几个概念就够了:
| 概念 | 一句话解释 | 产品类比 |
|---|---|---|
| Router(路由) | 把 URL 翻译成"用户想看什么" | 像客服,根据用户说的关键词分派到正确的处理部门 |
| Widget(数据层) | 从数据库里取数据的工具 | 像数据库的查询接口,一句话就能取到文章列表 |
| Theme(主题) | 负责"画页面"的那套代码 | 像 PPT 模板,同一套数据换不同模板就完全不同 |
| Plugin(插件) | 给 Typecho 加功能的扩展 | 像 Chrome 扩展,不改核心代码就能加功能 |
| 模板(Template) | Theme 里的具体文件,一个文件对应一种页面 | 像每个页面类型的设计稿 |
💡 你需要关心的只有两件事:Theme(主题)是你日常改的地方;Plugin(插件)是你装完就很少动的东西。Router 和 Widget 是 Typecho 核心,基本不需要碰。
你的系统架构一览
最外层(绿色块)就是你的主题,里面的核心和数据库一般不用动。
3. 一次访问的完整生命周期
以你博客上的一篇文章为例,URL 是 http://zi-yan.top/index.php/archives/72/:
用大白话翻译上面的流程图:
| 步骤 | 谁干的? | 做了什么? |
|---|---|---|
| ① | 浏览器 | 你输入了网址,浏览器发给服务器 |
| ② | Typecho 核心 | index.php 是唯一入口,所有请求都经过它,它把系统环境初始化好 |
| ③ | Typecho Router | 看 URL 里的 archives/72,知道"这是要看第 72 篇文章" |
| ④ | Typecho Widget | 连 MySQL 数据库,查 contents 表,取出第 72 篇文章的标题、正文、时间等 |
| ⑤ | 插件 | 如果装了 COS 上传、Album 相册等插件,它们会在此时介入 |
| ⑥ | 你的主题 | Typecho 把取好的数据“喂给”主题,主题的 post.php 把数据填进 HTML 模板 |
| ⑦ | 浏览器 | 收到完整的 HTML,渲染成你看到的文章页面 |
💡 关键领悟:主题只参与步骤 ⑥。前面 5 步 Typecho 都帮你做完了。主题的工作就是——Typecho 把菜备好了(数据),你来摆盘(展示)。
4. Single-master 主题全貌
4.1 你的主题有哪些文件?
按"必知程度"分三个层级:
| 层级 | 文件 | 干什么的 |
|---|---|---|
| ★ 必知 | index.php |
首页:文章列表 |
| ★ 必知 | post.php |
文章详情页:一篇文章的完整显示 |
| ★ 必知 | page.php |
独立页面:「关于我」等 |
| ★ 必知 | archive.php |
分类/标签/搜索结果页 |
| ★ 必知 | single.php |
工具类(夜间模式、时间格式化等) |
| ★ 必知 | functions.php |
后台外观设置(12 个开关和输入框) |
| ★ 必知 | single.css |
所有样式(颜色、布局、字体大小) |
| ★ 必知 | single.js |
所有交互(夜间模式切换、返回顶部等) |
| 了解即可 | header.php |
HTML 头部 + 页面标题 + 社交分享标签 |
| 了解即可 | header-nav.php |
导航栏:菜单、搜索、登录 |
| 了解即可 | footer.php |
页脚:版权、JS 加载、灯箱初始化 |
| 了解即可 | comments.php |
评论列表 + 发表表单 |
| 了解即可 | tags.php |
标签云模板 |
| 了解即可 | Multiverse.php |
网格图片墙模板 |
| 了解即可 | custom.php |
空白模板,供二次开发用 |
| 了解即可 | MkEncrypt.php |
页面密码保护工具 |
| 了解即可 | 404.php |
页面没找到的错误页 |
⚠️
static/kico.css、static/kico.js、static/prism.js、static/font-awesome/、static/Lens/、static/Multiverse/— 这些是第三方库,不要修改。
4.2 模板是怎么被自动选用的?
重要规律:Typecho 根据"页面类型"自动选用模板。
| 你访问的 URL | Typecho 判断的类型 | 自动选用 | 显示效果 |
|---|---|---|---|
/ |
首页 | index.php |
文章列表 |
/index.php/archives/72/ |
单篇文章 | post.php |
文章详情 |
/index.php/About.html |
独立页面 | page.php |
「关于我」 |
/index.php/category/album/ |
分类归档 | archive.php |
该分类下的文章列表 |
| (独立页面 + 后台选了模板) | 特殊模板 | Multiverse.php / custom.php 等 |
网格图片墙、自定义排版等 |
无论用哪个模板,都遵循同一个骨架:
header.php → HTML 头部、标题、导航、CSS
↓
index.php 等 → 页面主体内容(文章列表 or 文章 or 自定义内容)
↓
footer.php → 页脚、版权、JavaScript 脚本、灯箱
5. 模板渲染:页面是怎么"拼"出来的
5.1 首页(index.php)是怎么工作的
以你的首页为例,代码逻辑如下(看注释,不需要在意具体语法):
// 第一步:加载公共头部(HTML 框架 + 导航栏)
$this->need('header.php');
?>
<!-- 首页大标题区 -->
<section class="home-title">
<h1><?php $this->options->title() ?></h1> <!-- ← 显示站点名称,来自后台设置 -->
<span><?php $this->options->description() ?></span> <!-- ← 显示站点副标题 -->
</section>
<!-- 文章列表 -->
<section class="home-posts">
<?php while($this->next()): ?><!-- ← 循环:一篇文章一次 -->
<div class="post-item">
<h2><a href="<?php $this->permalink() ?>"><?php $this->title() ?></a></h2>
<p><?php $this->excerpt(100); ?></p> <!-- ← 摘要,截 100 字 -->
<div class="post-meta">
<time><?php $this->date(); ?></time> <!-- ← 发布日期 -->
<span><?php $this->category(','); ?></span> <!-- ← 分类 -->
<?php if(显示评论数设置打开了): ?>
<span><?php $this->commentsNum('%d °C'); ?></span> <!-- ← 评论数 -->
<?php endif; ?>
</div>
</div>
<?php endwhile; ?>
</section>
<?php $this->pageNav('«', '»'); ?><!-- ← 分页:上一页/下一页 -->
<?php $this->need('footer.php'); ?><!-- ← 加载公共页脚 -->
一句话总结:首页 = 一个循环 while($this->next()),把每篇文章的标题、摘要、日期、分类一行一行画出来。分页切换由 pageNav() 自动处理。
5.2 文章页(post.php)的独有功能
与首页不同,文章页多了几个专属区块:
| 区块 | 代码位置 | 功能 |
|---|---|---|
| 老文章提醒 | if(time() - $this->modified >= 15552000) |
文章修改超过 180 天,显示「这篇文章上次修改于 XXX 天前」 |
| 上一篇/下一篇 | $this->thePrev() / $this->theNext() |
文章底部的导航链接 |
| 标签 | $this->tags() |
显示文章标签(由 functions.php 的 archive_meta 设置控制) |
| 作者信息 | if($this->options->author_text) |
如果后台填了"作者信息",显示作者头像+介绍 |
| 评论区 | $this->need('comments.php') |
引入评论模板 |
5.3 归档页(archive.php)—— 分类/标签/搜索的共用模板
archive.php 复用了首页的列表结构,但多了两件事:
- 标题动态变化:在分类页显示「"技术"」,在标签页显示「含标签"生活"的文章」,在搜索页显示「含关键词"typecho"的文章」
- 搜索结果为空时:显示「没有找到结果 (QWQ)」
5.4 独立页面(page.php)
和文章页几乎一样,区别是没有上一篇/下一篇、没有标签、没有作者信息。就是一个干净的页面内容显示。
6. 数据流:数据库的信息怎么跑到页面上
这部分是理解"模板里写的东西什么意思"的关键。
核心模式:$this->xxx() = 取数据 + 显示
你在模板里看到的所有 $this->xxxx() 调用,本质上都是 Typecho 已经帮你从数据库取好的数据。记住这个对应表:
| 模板里的写法 | 实际取的数据 | 来自数据库的哪个字段 |
|---|---|---|
$this->title() |
文章标题 | contents.title |
$this->content() |
文章正文(HTML) | contents.text |
$this->excerpt(100) |
文章摘要(截 100 字) | contents.text 的前 100 字 |
$this->date() |
发布日期 | contents.created |
$this->permalink() |
文章链接 | 动态生成 |
$this->category() |
分类名称 | metas 表 |
$this->tags() |
标签列表 | metas 表 |
$this->commentsNum() |
评论数量 | comments 表统计 |
$this->author() |
作者名称 | users 表 |
$this->options->title() |
站点名称 | 后台设置的"站点名称" |
$this->options->description() |
站点副标题 | 后台设置的"站点描述" |
$this->options->xxx() |
后台各项设置值 | functions.php 注册的 12 个设置项 |
$this->fields->xxx |
自定义字段 | fields 表(CustomFields 插件) |
$this->is('post') |
判断当前是否文章页 | —(不是数据,是判断条件) |
自定义字段:给页面加"额外数据"
Typecho 自带一个"自定义字段"系统。在编辑文章/页面时,可以给页面附加任意键值对。这在相册场景中大量使用:
| 用法 | 例子 | 代码 |
|---|---|---|
| 给页面加描述 | about = "这是我的摄影集" | $this->fields->about |
| 给页面加密码 | password = "123456" | $this->fields->password |
| 给页面加社交链接 | Twitter = "https://..." | $this->fields->Twitter |
| 给照片墙加图片数据 | photos = '[{"url":"...","desc":"照片"}]' | 通过 CustomFields 插件的 API 读取 |
7. 前端交互:页面上那些"魔法"怎么实现的
所有你眼睛能看到的交互效果,由两个文件控制:
| 文件 | 角色 | 内容 |
|---|---|---|
static/single.css |
样式 | 颜色、布局、字体大小、响应式(手机适配)、夜间模式配色 |
static/single.js |
行为 | 点击响应、切换状态、动态生成目录等 |
single.js:Paul_Single 类
这个类在页面底部(footer.php)被初始化:
varsingle=newPaul_Single({
copyright:true,// 复制提醒(来自后台 copy_notice 设置)
night:true// 夜间模式(来自后台 night_mode 设置)
});
6 个核心功能:
| 方法 | 功能 | 用户能看到的效果 |
|---|---|---|
night() |
夜间模式切换 | 点击左上角图标,全站变暗/变亮 |
tree() |
文章目录生成 | 文章右侧自动出现"悬浮目录" |
to_top() |
返回顶部 | 滚动后右下角出现"↑"按钮 |
header() |
移动端菜单 | 小屏幕上汉堡菜单展开/收起 |
comment_list() |
评论高亮 | @回复时高亮定位到被回复的评论 |
links() |
复制提醒 | 复制文章内容时弹窗提示 |
single.css:主题的"皮肤"
single.css 约 500 行,按区域分为 6 块:
| 区块 | 行号范围(约) | 控制什么 |
|---|---|---|
| 0 全局 | 变量 + 基础 | 主题色 --blue: #6f9fc7、字体、夜间模式变量覆写 |
| 1 页眉 | header | 导航栏、汉堡菜单、搜索框样式 |
| 2 正文 | main | 文章排版、目录样式、图片、表格 |
| 3 页尾 | footer | 页脚信息栏、版权区 |
| 4 附加 | 额外 | 打印样式、Prism 代码块配色 |
💡 想改颜色?去
single.css找:root里的 CSS 变量,改一个变量全站生效。
8. 关键文件逐个讲解(产品经理版)
8.1 single.php — 核心工具类
这是主题的"瑞士军刀",提供了 4 个全局函数:
| 方法名 | 作用 | 怎么用的 |
|---|---|---|
Single::update() |
检查主题更新 | functions.php 调用,在后台显示更新信息 |
Single::is_night() |
判断夜间模式 | header.php 的 <body> 标签里调用,决定加载深色/浅色样式 |
Single::tran_time($ts) |
时间戳转友好格式 | comments.php 里用,「3 天前」「2 个月前」就是它算的 |
Single::post_image() |
取文章第一张图 | header.php 里用,给社交分享(微信/微博)提供封面图 |
8.2 functions.php — 后台外观设置
这个文件只有一个函数 themeConfig(),作用是注册 Typecho 后台"外观设置"里的 12 个配置项。
你进入 控制台 → 外观 → 设置外观 看到的所有开关和输入框,都来自这个文件:
| 设置项 | 类型 | 作用 |
|---|---|---|
favicon |
文本框 | 站点图标 |
background |
文本框 | 背景图 |
home_social |
文本框 | 首页社交链接 |
custom_css |
文本框 | 自定义 CSS |
custom_script |
文本框 | 统计代码 |
author_text |
文本框 | 文章底部作者介绍 |
night_mode |
单选 | 夜间模式:关闭/自动/始终 |
copy_notice |
单选 | 复制内容时是否弹窗提醒 |
widget_set |
单选 | 页脚信息栏:开/关 |
archive_meta |
多选 | 首页/归档显示哪些元信息 |
post_meta |
多选 | 文章页显示哪些元信息 |
hidden_categories |
文本框 | 对未登录用户隐藏的分类 |
💡 想加一个新设置?在这个文件里参照现有的格式加一行就行。
8.3 header.php — HTML 头部
产出物:网页的 <head> 区域 + <body> 开始标签 + 导航栏引入。
关键内容:
- 页面标题:根据页面类型动态生成(首页显示站名,文章页显示「文章名 - 站名」)
- CSS 加载:kico.css → single.css → Font Awesome 图标
- Open Graph 标签:给微信/微博等社交平台分享用的标题、描述、封面图
- 夜间模式判断:Single::is_night() 决定 <body> 有没有 dark-theme 类名
8.4 header-nav.php — 导航栏
产出物:页面顶部的导航条(桌面端 + 移动端)。
包含:
- 夜间模式切换按钮
- 桌面端:登录/用户下拉菜单 + 搜索框
- 移动端:汉堡菜单 → 侧边滑出菜单(首页 / 分类 / 相册 / 关于我 / 进入后台)
- 隐藏分类逻辑:如果在 functions.php 里设了"隐藏分类",未登录用户看不到这些分类
- 遮罩层(点击遮罩关闭菜单)
8.5 footer.php — 页脚 + 所有 JS
产出物:页面底部信息 + 所有 JavaScript 脚本加载。
关键内容:
- 返回顶部按钮 + 目录切换按钮
- 页脚信息栏(可由后台"widget_set"开关控制):最新文章 / 时光机(按月份归档)/ 最近评论
- 版权信息:年份 + 站点名 + 主题 credit + ICP 备案号
- JS 加载顺序:kico.js → single.js → prism.js → 初始化 Paul_Single
- fancybox 灯箱:CDN 加载,图片点击放大
8.6 comments.php — 评论区
产出物:评论列表 + 评论发表表单。
包含:
- 评论者头像:QQ 邮箱用腾讯头像 API,其他邮箱用 Gravatar
- 友好时间:评论时间用 Single::tran_time() 显示(如"3 天前")
- @回复显示:回复时显示「@原作者名」
- 待审核标记:未审核评论显示审核提示
- 响应式表单:已登录用户看简化表单,未登录需要填昵称+邮箱+网址
8.7 MkEncrypt.php — 页面密码加密
一个独立的加密工具,可为 Typecho 独立页面添加密码保护功能。
工作流程:
1. 访客打开加密页面 → 显示密码输入框(整页遮罩)
2. 输入正确密码 → 设置 Cookie(存 41 天),显示内容
3. 密码错误 → 显示「密码不对!请重试」
4. 已有 Cookie 的用户 → 直接看内容
💡 任何自定义模板都可以引入
require_once('MkEncrypt.php')然后通过$this->fields->password自定义字段控制是否加密。
9. 相册:Album 插件
你的网站目前通过 Album 插件来展示相册,它有自己的路由(/album/),不经过主题的 index.php / page.php 流程。
| 组件 | 说明 |
|---|---|
| Album 插件 | 独立路由 /album/,自带数据库表、上传接口、展示页面 |
| 导航链接 | header-nav.php 中的「相册」链接指向 /album/ |
| 与主题的关系 | Album 插件的输出独立于主题,但共享同一套数据库和用户系统 |
已移除的相册模板
photo-wall.php(瀑布流照片墙)和 Lens.php(全屏相册)已于 2026-07-09 删除。如果你需要新的照片展示方式,使用 Album 插件或创建新的自定义模板。
10. 改东西该去哪改?速查表
| 你想改什么 | 去改哪个文件 | 具体改哪里 |
|---|---|---|
| 站点名称、副标题 | Typecho 后台(不是代码!) | 控制台 → 设置 → 基本 |
| 站点图标、背景图 | Typecho 后台 | 控制台 → 外观 → 设置外观 |
| 主题主色调 | static/single.css |
搜索 --blue: #6f9fc7,改颜色值 |
| 夜间模式颜色 | static/single.css |
搜索 .dark-theme,改里面的颜色变量 |
| 导航栏菜单项 | header-nav.php |
搜索 "首页",改 <a href=...> 标签 |
| 首页显示几篇文章 | Typecho 后台 | 控制台 → 设置 → 阅读 → 每页文章数 |
| 首页文章列表显示哪些信息 | Typecho 后台 | 控制台 → 外观 → 设置外观 → archive_meta |
| 文章底部作者介绍 | Typecho 后台 | 控制台 → 外观 → 设置外观 → author_text |
| 版权信息文字 | footer.php |
搜索 "All Rights Reserved" |
| ICP 备案号 | footer.php |
搜索 "ICP备案号" |
| 统计代码 | Typecho 后台 | 控制台 → 外观 → 设置外观 → custom_script |
| 加一个新的后台设置项 | functions.php |
参照现有代码,加一个新的 Form_Element_* |
| 加一种新的页面模板 | 新建 xxx.php |
参照 custom.php,第 2 行加 @package custom |
| 隐藏某些分类 | Typecho 后台 | 控制台 → 外观 → 设置外观 → hidden_categories |
| 评论表单文字 | comments.php |
搜索 "快来评论支持吧" |
| 404 页文字 | 404.php |
搜索 "页面不见了" |
| 部署到生产 | 按 MEMORY.md 流程 | git checkout main && git merge dev → 打包 → scp |
11. 常见术语对照表
| 技术术语 | 白话解释 |
|---|---|
| PHP | 一种服务器端编程语言,Typecho 用它写的 |
| PHP 模板 | 后缀 .php 但主要是 HTML 的文件,里面夹了一些 <?php ?> 取数据的代码 |
$this |
指当前页面的"数据对象",你可以把它想象成一篇文章的所有信息 |
$this->options |
网站全局设置(站点名、描述、后台各项开关) |
$this->fields |
当前页面的"自定义字段"(额外的键值对数据) |
$this->need('xxx.php') |
加载另一个 PHP 文件进来,类似"在这里插入 header 文件" |
| Widget | Typecho 的数据获取工具,每种数据有一个 Widget(文章、分类、评论各不同) |
| MySQL | 关系型数据库,所有内容(文章、评论、设置)都存在里面 |
| CSS | 样式表,控制颜色、字体、布局、响应式 |
| JS(JavaScript) | 前端脚本,控制点击响应、动画、切换等交互行为 |
| OG 标签 | Open Graph 标签,给微信/微博分享时提供标题和封面图 |
| CDN | 内容分发网络,JS/CSS/图片从离用户最近的服务器加载,更快 |
| Cookie | 浏览器端的小存储,用来记住"夜间模式"偏好、"加密页面密码"等 |
| 路由(Route) | URL 和页面模板的对应关系,如 /archives/72 → post.php |
| 自定义字段(Field) | 文章的附加属性,如相册的 "password"、"photos"、"about" 等 |
| fancybox | 一个图片灯箱 JS 库,点图片后弹出大图/相册预览 |
后记
这份文档覆盖了 Typecho 和 Single-master 主题的所有核心逻辑。作为产品经理,你不需要能写代码,但知道每一块代码"管什么"、"在哪里改",会让你和开发协作时事半功倍。
如果某个部分有疑问,或者想深入了解某个特定功能,随时可以问我。
文档生成于 2026-07-09 · 基于 Single-master v2.1 · Typecho 1.2.1
没有评论