基于 mulingyuer/Typecho_Theme_JJ 深度改进,全面适配 PHP 8.3, 修复兼容性 bug 20+ 处,新增面包屑、进度条、上下篇、代码复制等多项实用功能。
以下为 mulingyuer 开发的 JJ 主题全部功能,致敬原作者。
原主题仅支持 PHP 7.2 ~ 8.2,在 PHP 8.3 + Typecho 1.3 环境下有多处致命错误。以下为全部修复清单。
根因:unserialize($that->fields) 在 PHP 8.3 中当 fields 非字符串时返回 false,直接传给 array_key_exists() 触发致命错误。另外 Typecho 1.3 中 $this->fields 返回 Config 对象,get_object_vars() 无法获取内部数据。
解决:新增 jj_fields_to_array() 和 jj_field_get() 两个辅助函数,改用 Config::toArray() 直接获取内部数组,所有字段访问统一走安全封装。
| 函数 | 问题 | 修复方式 |
|---|---|---|
| articleViews() | unserialize → false 传给 array_key_exists | 改用 jj_field_get() |
| getLikeCount() | $that->fields->likes 对字符串/Config 报错 | 改用 jj_field_get() |
| articleThumbnail() | $that->fields->titleImg/thumb | 改用 jj_field_get() |
| getArticleTitleImg() | $that->fields->titleImg | 改用 jj_field_get() |
| getArticleTheme() | $that->fields->markdownTheme | 改用 jj_field_get() |
| getMarkdownTheme() | $that->fields->markdownTheme/highlightTheme | 改用 jj_field_get() |
| promo() | unserialize → false 传 array_key_exists;inc/dec 未定义键 | jj_fields_to_array() + ?? 0 |
| viewsCounter() | Cookie 返回值可能非字符串传 explode | 新增类型判断 |
| pushStickyArticles() | $cidArticle->fields->thumb;$stack 非数组 | jj_field_get() + is_array |
| getIdPosts() | explode 参数可能非字符串 | 加 (string) 强转 |
PHP 8.x 中 count(null)、foreach(null)、array_merge(false) 均触发 TypeError。全面扫描发现 27 处潜在风险,修复了以下 18 处。
| 文件 / 函数 | 风险 | 修复 |
|---|---|---|
| secondary_nav.php:5 | count($children) — getAllChildren() 可返回 null | 加 is_array() 前置检查 |
| article_card.php:44 | array_slice($this->tags) — $this->tags 可能 null | 三元判断 is_array() |
| articles_related.php:37 | 同上 | 同上 |
| generateTreeList() | count($list) 当 null | 入口加 !is_array → array() |
| removeChildren() | foreach 当 null | 入口加 !is_array → return array() |
| generateTreeTemplate() | count($arr) 当 null | 入口加 !is_array → array() |
| getDirectoryTree() | 全局 $catalog 可能 null | is_array() + !empty() |
| getJJDirectoryTree() | $catalog 给 array_replace_recursive | !is_array → array() |
| todoListFormatted() | preg_replace 非字符串 | !is_string → return |
| articleReadingTime() | mb_strlen 非字符串 | !is_string → $text="" |
| remove_comment_p() | preg_replace 非字符串 | !is_string → return |
| getAdminUrl() | strpos/substr 非字符串 | !is_string → $page="" |
迁移文章使用 ##、** 等 MD 语法,但页面显示原始文本。根因是 Typecho 通过 <!--markdown--> 前缀判断是否 MD 内容,WP 迁移文章无此前缀。
| 文件 | 修改 |
|---|---|
| php_modules/markdown.php:13 | 最终方案:Markdown::convert($this->text) 直接强制解析,不依赖 isMarkdown 判断 |
| functions.php | 新增 jj_markdown_aware_excerpt() 辅助函数,检测 MD 特征并强制解析 |
| functions.php:1205 | getArticleSummary() 改用新函数 |
| functions.php:350 | blogDescription() 改用新函数(修复 meta description raw MD) |
| functions.php:1599 | themeInit() 中 addAnchorPoint() 前用 Markdown::convert() 强制解析(修复目录树) |
| article_card.php:28 | 首页列表摘要改用 jj_markdown_aware_excerpt() |
配套修复:WP2TypechoPlus 插件 Action.php 新增 isMarkdownContent() 方法,导入时自动添加 <!--markdown--> 前缀,后续导入文章不需要依赖主题级强制解析。
| 问题 | 修复 |
|---|---|
| pageSize 在 Widget_Archive 构造后才生效 | functions.php 顶部提前注入 pageSize;themeInit 中设 $archive->parameter->pageSize 确保查询前生效 |
| 文章浏览量和点赞在 Typecho 1.3 始终为 0 | jj_fields_to_array() 改用 Config::toArray() 替代 get_object_vars() |
| 文件上传失败(usr/uploads 年份目录 owner 为 root) | chown -R www:www;Upload.php mkdir 简化递归逻辑 |
| 关键词拼接用 + 而非 . | functions.php:529 修正为 . 拼接 |
| prev_next.php preg_match 未保护 | 加 if 保护防未定义数组键 |
| pushStickyArticles / getHomeRecommendedArticleList return 应 continue | 改为 continue |
| home/nav.php 硬编码 URL | 改为 siteUrl() |
| sitemap URL 可能缺斜杠 | 加 rtrim 处理 |
| index.php getTotal() 弃用警告 | 加 intval(null ?? 0) |
| 浏览器控制台 webmanifest MIME 错误 + 欢迎日志 | 复制 .json 扩展名文件;default_head.php 拦截 console.log 过滤 |
在修复兼容性之外,还新增了以下实用功能。
新增 php_modules/breadcrumb.php,支持文章/页面/分类/标签/归档/搜索页,含 Schema.org BreadcrumbList 结构化数据
阅读时间旁显示字数;顶部 sticky 3px 蓝色进度条,requestAnimationFrame 驱动
新增 post/prev_next.php,CSS Grid 双列卡片布局,版权声明后展示
markdown.php 每段代码右上角悬停显示复制按钮,支持 clipboard API + execCommand 降级
搜索页顶部显示关键词 + 结果数;文章卡片标题/描述中关键词高亮(<mark>),createDocumentFragment 防 XSS
header.php 搜索表单 onsubmit 拦截,用 JS 在中文字符间自动插入空格,利用 Typecho 多词 LIKE 匹配
建站时长自动计算(X 年 X 月 X 天);版权年份智能显示(2020-2026);外观设置可配置建站日期
外观设置新增 siteLogo/siteAvatar 配置项,填入图片 URL 即可替换默认图标和 Gravatar
外观设置可选「分页显示」或「无限滚动」;每页文章数可自定义(5-30),默认改为分页 10 篇
首页侧边栏新增 RSS 订阅和站点地图入口卡片
新增 archives.php 自定义模板(@package custom),分页 20 篇/页,右侧最新文章列表
notification.php →「消息通知」;links.php →「友情链接」;archives.php →「文章归档」
三步启用主题。
从下方网盘链接下载 JJ 主题压缩包。
解压后将文件夹上传到 usr/themes/ 目录。
Typecho 后台 → 控制台 → 外观,找到「JJ」主题,点击启用。