Typecho主题二次开发:从小白到能改模板

说实话,我用Typecho已经两年多了,一直用的都是别人做的主题。功能不满意的地方,要么忍,要么换个主题重新折腾。直到有一天我实在受不了某个主题的评论样式,花了一晚上时间自己改了改,才发现自己其实也可以折腾这个。

Typecho的主题系统其实挺简单的,就那么几个PHP文件,改起来比WordPress还容易上手。今天写篇文章记录一下我是怎么从"只会装主题"到"能自己动手改模板"的,希望对想折腾Typecho的同好有点帮助。

为什么选择Typecho?

先简单说一下为什么我一直用Typecho而不是WordPress或Z-Blog。

Typecho最大的特点就是"轻"。整个程序才几百KB,启动速度飞快,占用内存极低。我那台512MB内存的小VPS跑Typecho稳得一批,跑WordPress就经常报警。

后台也简洁,没有WordPress那么多花里胡哨的功能菜单,新手友好度很高。

当然Typecho也有缺点:主题和插件生态没有WordPress丰富。但对于我这种技术博客来说,够用了。

Typecho主题的文件结构

先搞清楚Typecho主题的文件结构,不然改起来会一头雾水。

一个完整的Typecho主题,核心文件通常有这些:

```

/usr/themes/你的主题名/

├── style.css # 主题样式表,必须有

├── index.PHP # 首页模板,必须有

├── header.php # 页头(导航、head标签),必须有

├── footer.php # 页脚,必须有

├── functions.php # 主题函数,可以有

├── post.php # 文章页模板

├── page.php # 独立页面模板

├── archive.php # 归档页模板

├── category.php # 分类页模板

├── tag.php # 标签页模板

├── 404.php # 404页面

└── sidebar.php # 侧边栏(可选)

```

刚装好的主题一般只有style.css、index.php、header.php、footer.php四个文件,其他模板页如果不存在,会自动 fallback 到 index.php。

理解了这个,就能明白为什么改某些页面需要修改对应模板文件,而改全局样式只需要动style.css。

我的第一次改模板经历

我第一次动手改Typecho主题,是因为觉得文章的发布时间显示格式不好看。默认显示的是"2025年6月10日 14:30",我想改成"3天前"这种相对时间。

我先打开header.php看了一下,搜索"time"关键词,找到显示时间的函数是 `{$article->dateWord()}`,查了一下文档,发现改成 `{$article->date('Y-m-d')}` 就直接改成了我想要的格式。

整个过程不到10分钟,搞定之后特别有成就感……虽然只是改了一个日期格式,但感觉打开了新世界的大门。

进阶:修改主题functions.php

functions.php是Typecho主题的"大脑",几乎所有自定义功能都在这里实现。

我在这里做了几件事:

一是添加自定义字段。比如我想给每篇文章加一个"推荐指数"的评分。我先在functions.php里注册一个字段:

```php

function themeFields($layout) {

$rating = new Typecho_Widget_Helper_Form_Element_Text(

'rating',

NULL,

'5',

'推荐指数(1-10)',

'给文章打个分吧'

);

$layout->addItem($layout);

}

```

然后在文章页面里调用这个字段显示评分:

```php

fields->rating): ?>

评分:fields->rating(); ?>/10

```

二是修改评论列表样式。Typecho默认的评论样式比较朴素,我想改成嵌套评论的样子,就在functions.php里加了评论回调函数,重新定义了评论的HTML结构。

实战:给博客加一个"相关文章"模块

最能体现"自己动手"价值的功能,我认为是相关文章推荐模块。默认Typecho没有这个功能,得自己写。

在post.php里找到文章内容的结束标签,在它下面加一段代码:

```php

Typecho主题二次开发:从小白到能改模板-第1张图片-无双博客

相关推荐

$db = Typecho_Db::get();

$rows = $db->fetchAll($db->select()->from('table.contents')

->where('status', 'publish')

->where('created < ?', $this->created)

->where('type', 'post')

->where('categories.cid = table.contents.cid')

->join('table.relationships', 'table.relationships.cid = table.contents.cid')

->where('table.relationships.mid = ?', $this->categories[0]['mid'])

->order('table.contents.created', Typecho_Db::SORT_DESC)

->limit(5));

if ($rows): ?>