网站维护页

文档编号 08

08 - 维护文档公开页面

日期:2026-04-29

背景

.maintenance/ 目录下的 Markdown 维护文档通过 Typecho 独立页面对外公开,支持后续动态扩展,无需改动模板代码。


实现方案

模板文件

文件模板名用途
{TYPECHO_ROOT}/usr/themes/classic-22/maintenance-index.php维护文档目录目录页:展示 README.md + 文档列表卡片
{TYPECHO_ROOT}/usr/themes/classic-22/maintenance-doc.php维护文档详情详情页:动态加载对应 .md 文件

动态文件映射规则

详情页模板通过当前页面的 slug 末尾两位数字 自动匹配对应 .md 文件:

slug: maintenance-03
        ↓ preg_match('/(\d{2})$/', slug)
      prefix = "03"
        ↓ glob("{TYPECHO_ROOT}/.maintenance/03-*.md")
      file = "03-bangumi-api-notes.md"

代码位于 maintenance-doc.php(在 header.php 之后执行,见下方注意事项):

preg_match('/(\d{2})$/', $this->slug, $m);
$_docFileNum = $m[1] ?? null;
$_hits = glob(__DIR__ . '/../../../.maintenance/' . $_docFileNum . '-*.md');
$_mdFile = $_hits[0] ?? null;

文档列表收录规则

目录页通过 slug 前缀匹配(而非父子关系)收录文档页,与 Typecho 页面层级完全解耦:

while ($_pages->next()) {
    if (preg_match('/^maintenance-(\d{2})$/', $_pages->slug)) {
        // 收录进文档列表
    }
}
// 按 slug 升序排列,确保 01→02→... 顺序
usort($childPages, fn($a, $b) => strcmp($a['slug'], $b['slug']));

Markdown 渲染

使用 Typecho 内置静态方法:

echo \Utils\Markdown::convert(file_get_contents($mdFile));

Markdown 中第一个 h1 与页面标题重复,通过 CSS 隐藏:

.maint-content > h1:first-child { display: none; }

导航栏集成

header.php 中增加了 slug 过滤,维护文档详情页不出现在导航栏:

// slug 符合 maintenance-NN 格式的详情页不进入导航栏
if (preg_match('/^maintenance-\d{2}$/', $allNavPages->slug)) continue;

效果:

  • "网站维护目录" 作为普通顶级页面出现在导航栏(单链接,无下拉)
  • maintenance-01 ~ maintenance-NN 均不出现在导航栏
  • 用户通过维护目录页的文档列表卡片导航到各详情页

重要实现注意:Widget 调用顺序

Typecho 的 Widget\Contents\Page\Rows::alloc() 是共享实例,迭代器消耗后不会自动重置。

错误做法(导致 header.php 导航栏缺项):

// ❌ 在 header.php 之前调用 alloc() 并迭代
\Widget\Contents\Page\Rows::alloc()->to($pages);
while ($pages->next()) { ... }
?>
<?php $this->need('header.php'); // header.php 拿到已消耗的 widget,导航栏为空

正确做法

// ✅ header.php 之前只做文件系统操作,不调用 Widget
$_docSlug = $this->slug;
$_mdFile = ...; // glob() 操作
?>
<?php $this->need('header.php'); // header.php 正常获取完整页面列表

// header.php 之后再调用 alloc()
\Widget\Contents\Page\Rows::alloc()->to($pages);
while ($pages->next()) { ... }

Typecho 后台配置

页面结构

所有维护文档页面均为独立顶级页面(无父子关系),通过 slug 前缀与目录页关联:

标题Slug模板
网站维护目录maintenance维护文档目录
01 架构分析maintenance-01维护文档详情
02 JSON 工具页面maintenance-02维护文档详情
03 Bangumi API 笔记maintenance-03维护文档详情
04 GitHub API 笔记maintenance-04维护文档详情
05 Steam API 笔记maintenance-05维护文档详情
06 动态页面笔记maintenance-06维护文档详情
07 导航下拉菜单maintenance-07维护文档详情
08 维护文档公开页面maintenance-08维护文档详情

模板识别原理

Typecho 通过扫描主题目录 .php 文件的 docblock 头部识别自定义模板:

  • @package custom → 标记为可选模板(必须)
  • 第一行描述文字 → 作为模板名称显示在后台下拉(Template Name: 行实际上不被解析,无效)

新增维护文档流程

  1. .maintenance/ 新建 {NN}-{描述}.md
  2. 更新本 README.md 文档索引表
  3. 在 Typecho 后台新建独立页面:

    • 标题:{NN} {描述}
    • Slug:maintenance-{NN}
    • 模板:维护文档详情
    • 父页面:(不需要父子关系)

目录页的文档列表会自动收录新页面,无需改动任何模板代码


样式说明

两个模板均内嵌 CSS,使用 pico.css CSS 变量,自动适配深色/浅色模式:

  • .maint-content — Markdown 正文容器(h1~h6、table、code、pre、blockquote 均有样式)
  • .maint-content > h1:first-child — 隐藏 Markdown 首个大标题(与页面标题重复)
  • .maint-subpages-grid — 文档列表卡片网格(仅目录页)
  • .maint-breadcrumb — 面包屑导航(仅详情页,使用 <p> 标签避免 pico.css nav 样式干扰)
  • .maint-doc-header — 文档标题区(仅详情页)