Typecho 主题开发从零到一:模板层级、自定义字段与插件钩子

Typecho 主题开发从零到一:模板层级、自定义字段与插件钩子

admin
2026-11-02 / 0 评论 / 2 阅读 / 约 10 分钟 / 正在检测是否收录...

模板层级与继承规则

Typecho 的模板系统遵循“约定优于配置”的原则,核心在于文件名与请求类型的映射。所有模板文件位于主题目录下(如 usr/themes/mytheme/),入口文件固定为 index.php。当用户访问不同页面时,Typecho 按以下顺序查找并加载模板:

  1. 首页:优先 index.php,若不存在则回退到 archive.php,最后是 index.php(必须存在)。
  2. 文章页:post.php → single.php → archive.php → index.php。
  3. 独立页面:page.php → single.php → archive.php → index.php。
  4. 分类/标签/归档:category.php / tag.php / date.php → archive.php → index.php。
  5. 搜索页:search.php → archive.php → index.php。
  6. 404 页面:404.php → index.php。
注意:模板继承是“回退”而非“覆盖”。若 post.php 不存在,Typecho 会使用 single.php,而不是自动包含 index.php 的内容。

此外,functions.php 是主题的功能入口,用于注册钩子、定义辅助函数。comments.php 负责评论区域渲染。所有模板文件最终通过 $this 对象访问当前请求的数据。

$this 常用方法与自定义字段读取

在模板中,$this 是 Widget_Archive 或 Widget_Abstract 的实例,封装了几乎所有运行时数据。常用方法如下:

  • $this->archiveTitle():输出当前页面的标题(如分类名、文章标题)。
  • $this->title():输出文章标题。
  • $this->content():输出文章正文(已过滤)。
  • $this->excerpt():输出摘要。
  • $this->permalink():输出当前文章/页面的永久链接。
  • $this->date():输出发布时间,可传格式参数。
  • $this->author():输出作者名。
  • $this->categories():输出分类链接。
  • $this->tags():输出标签链接。
  • $this->commentsNum():评论数量。
  • $this->fields:当前文章的自定义字段对象(数组)。

自定义字段(Custom Fields)是 Typecho 内置的扩展机制,允许在文章编辑页添加键值对。读取方式有两种:

// 方式一:通过 $this->fields 直接读取
$price = $this->fields->price; // 若字段不存在,返回 null

// 方式二:使用 getField 方法(需在 functions.php 中定义辅助函数)
function getCustomField($key, $default = '') {
    $fields = Typecho_Widget::widget('Widget_Abstract_Contents')->fields;
    return isset($fields->$key) ? $fields->$key : $default;
}
自定义字段的值默认经过 htmlspecialchars 转义,若需输出 HTML,请使用 $this->fields->price 后手动处理。

插件钩子:Plugin::factory 注册与调用时机

Typecho 的插件钩子(Plugin Hooks)是扩展核心行为的关键。钩子通过 Typecho_Plugin::factory() 注册,返回一个代理对象,允许你在特定时机注入代码。注册通常在 functions.php 或插件文件的 activate 方法中完成。

注册方式:

Typecho_Plugin::factory('Widget_Archive')->beforeRender = array('MyPlugin', 'beforeRender');

调用时机:

  • Widget_Archive 的 beforeRender:在模板渲染前触发,可修改 $this 对象的数据。
  • Widget_Archive 的 afterRender:在模板渲染后触发,适合输出额外内容。
  • Widget_Contents_Post_Edit 的 finishPublish:文章发布后触发,用于保存自定义字段。
  • Widget_Feedback 的 comment:评论提交后触发,用于过滤或通知。
钩子名称区分大小写,且必须与核心类名完全一致。未注册的钩子不会报错,但也不会执行。

完整可运行示例:为文章添加“阅读时长”字段

下面实现一个主题功能:在文章编辑页添加“阅读时长”自定义字段,并在文章页输出。

第一步:在 functions.php 中注册钩子

<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;

// 注册文章发布/编辑完成时的钩子,保存自定义字段
Typecho_Plugin::factory('Widget_Contents_Post_Edit')->finishPublish = array('MyTheme', 'saveReadingTime');

class MyTheme {
    // 保存字段
    public static function saveReadingTime($contents, $class) {
        $fields = $class->request->get('fields');
        if (isset($fields['readingTime'])) {
            $contents['fields']['readingTime'] = $fields['readingTime'];
        }
        return $contents;
    }
}

// 辅助函数:获取阅读时长
function getReadingTime($default = '未知') {
    $fields = Typecho_Widget::widget('Widget_Abstract_Contents')->fields;
    return isset($fields->readingTime) ? $fields->readingTime : $default;
}

第二步:在 post.php 中输出

<article>
    <h1><?php $this->title(); ?></h1>
    <div class="meta">
        <span>阅读时长:<?php echo getReadingTime(); ?> 分钟</span>
    </div>
    <div class="content"><?php $this->content(); ?></div>
</article>

第三步:在文章编辑页添加字段输入框(通过 admin/write-post.php 的钩子或直接修改主题的 functions.php 注入表单)。

此示例展示了 Plugin::factory 的注册、$this->fields 的读取以及自定义字段的保存流程。注意:finishPublish 钩子返回的 $contents 必须原样返回,否则会丢失数据。

模板继承与钩子对比

特性模板继承插件钩子
作用范围页面渲染核心流程任意环节
修改方式覆盖文件注册回调
优先级文件存在即生效按注册顺序执行
典型用途布局、样式数据过滤、扩展字段
是否可逆删除文件即恢复需注销钩子

常见问题

1. 模板文件命名错误会导致什么?

Typecho 会回退到 index.php,若 index.php 也不存在,则直接报错。建议至少保留 index.php 和 style.css。

2. 自定义字段的值为什么输出为空?

检查字段是否在编辑页正确保存,以及是否在模板中使用了 $this->fields->key。若字段未定义,返回 null,需用 isset 判断。

3. 插件钩子注册后没有执行?

确认钩子名称与核心类完全一致,且注册代码在 activate 或 functions.php 中执行。部分钩子需要特定参数,参考官方文档。

4. 如何调试模板中的变量?

使用 var_dump($this->fields) 或 print_r($this->fields) 输出到页面,或开启 Typecho 的调试模式查看日志。

0

评论 (0)

取消