完美解决Typecho升级新版后无法在$item中直接获取文章/页面对应的permalink问题
完美解决Typecho升级新版后无法在$item中直接获取文章/页面对应的permalink问题
NianSir's BLOG

完美解决Typecho升级新版后无法在$item中直接获取文章/页面对应的permalink问题

NianSir
2024-05-16 / 0 评论 / 88 阅读

lw8ygwg3.png

前言

  一转眼博客平稳运行就过去两年了,玩是玩的不少,文章没码几篇,最近就想着好好调整一下认真写点博客,顺便也好记录下一些学习过程中的心得,就把博客升级顺便换个主题。
  本站使用的是开源博客程序Typecho,选择Typecho的理由很简单——开源、轻便、易扩展,几年前Typecho正式版1.1发布后官方就一直没有新消息了,还以为又一大开源项目就要隐退,没想到23年愚人节typecho官方社区突然发声——不是在开玩笑,我们回来了:Typecho1.2,接着官方社区又开始活跃起来了,距离最近的正式版发布就是1.2的修复版,在23年6月份发布,主要就是修复了一些高危漏洞,但开发版本已经更新到了1.3,本着尝鲜的原则NianSir也是很快的就更新到了最新版本(更新方法应该不用多说,找到这篇文章的同志们应该都是已经完成了更新)

  什么?你说你还不会更新?行吧,那就简单说说:

Typecho升级

  1. 备份好数据;
  2. 下载最新版Typecho压缩包,解压后重新打包 install.php、index.php、/var/整个文件夹、/admin/整个文件夹
  3. 到你的站点目录下解压这个新的压缩包覆盖替换这些内容(千万不要打包/usr/文件夹,一换一个不吱声);

​  完成这些工作后,重新访问后台(什么?你的后台进不去一堆PHP报错?新版本的PHP要求 ≥ 7.2,记得改好PHP版本再来),然后会有个提示确认更新Typecho的页面,选择确定更新后即可,如果你的站点启用了不支持高版本PHP的插件进入前台也是大概率一堆报错或者直接500错误,这个时候建议在后台全部禁用插件,主题换默认主题,然后再一个一个启用并观察前台是否报错,找出能用的插件,其他基本可以删掉了,其他问题常见的话网上也有很多大佬有给出解决方案,多找找就好。

解决Joe修改版中的permalink无法获取

​  扯了这么多题外话,该言归正传了,我遇到的问题就是升级到Typecho开发版1.3之后因为要换高版本PHP,干脆就直接换成了PHP8.1,再搭配上Joe主题(在此之前我一直使用小灯泡设计的splity主题,也是很不错的,就是单调了点,再加上splity主题原作者也很久不咕咕了,干脆就换个新的花哨点的主题)的修改版本,因为Joe官方主题在22年就停更了,而且很多资源都是用外链方式引入,很多资源也炸了,后来热爱Joe的粉丝团体有大佬做了进一步的优化和修正,就出来了现在的Joe修改版1.2.1,作者也在Github开源了,大家喜欢的话也可以去支持一下:https://github.com/jd82k/Joe/

独立页面的链接修复

​  但是在换上这个主题之后,我发现导航顶端的独立页面和侧边栏开启的随机文章推荐都出现了报错,问题都是Array中没有定义['permalink'],导致这两个地方a链接的href指向地址都无法获取,二话不说直接去看主题的源代码,根据第一个报错信息——独立页面的报错信息可以确定问题出在/usr/themes/Joe/module/header.php的第90行,通过查看这个文件的源代码可以看到第90行是这样的:

<a class="item <?php echo $this->is('page', $item['slug']) ? 'active' : '' ?>" href="<?php echo $item['permalink'] ?>" title="<?php echo $item['title'] ?>"><?php echo $item['title'] ?></a>

​  我们发现其中的问题就出在href通过 <?php echo $item['permalink'] ?> 来获取,接下来我们使用print_r来打印一下 $item 的内容,发现item中并没有permalink这一项,但是能找到slug也就是URL中使用的缩略名,于是解决这个地方的问题就很简单,只需要我们手动构造permalink即可,于是我把href的内容修改为:

<?php echo $this->options->siteUrl().$item['slug'].'.html' ?>

​  成功解决独立页面永久链接问题,这里其实在第一次修改的时候我发现href会默认补齐当前的路径地址,所以一开始我并没有添加 $this->options->siteUrl() 这一部分,后来测试的时候发现如果进入了站点子目录或者不在首页URL下这个生成的地址就会出错,于是去查阅Typecho开发文档发现有这么一个方法可以获取到站点链接。

热门文章的链接修复

​  接下来就是解决第二个地方的报错了——PC侧边栏的随机文章推荐。同样根据报错信息可以知道问题出在/usr/themes/Joe/public目录下的 function.php ,这是个纯PHP函数文件,大概在297行左右,热门文章获取函数中,我们可以看到代码是这样实现的:

/* 获取侧边栏作者随机文章 */
function getAsideAuthorNav()
{
    if (\Helper::options()->JAside_Author_Nav && \Helper::options()->JAside_Author_Nav !== "off") {
        $limit = \Helper::options()->JAside_Author_Nav;
        $db = \Typecho_Db::get();
        $prefix = $db->getPrefix();
        $sql = "SELECT * FROM `{$prefix}contents` WHERE cid >= (SELECT floor( RAND() * ((SELECT MAX(cid) FROM `{$prefix}contents`)-(SELECT MIN(cid) FROM `{$prefix}contents`)) + (SELECT MIN(cid) FROM `{$prefix}contents`))) and type='post' and status='publish' and (password is NULL or password='') ORDER BY cid LIMIT $limit";
        $result = $db->query($sql);
        if ($result instanceof \Traversable) {
            foreach ($result as $item) {
                $item = \Typecho_Widget::widget('Widget_Abstract_Contents')->push($item);
                $title = htmlspecialchars($item['title']);
                $permalink = $item['permalink'];
                echo "<li class='item'><a class='link' href='{$permalink}' title='{$title}'>{$title}</a>...</li>";
            }
        }
    }
}

​  在这段代码中随机获取文章实际上是通过查询数据库返回对应的数据条目,同样使用print_r打印一下 $item 中的内容,同样是没有permalink键,打开数据库管理工具,查看一下数据表的内容和结构:

lw8xlddk.png

  发现在文章数据表中能够直接使用的项只有cid、title、文章slug,并没有所属分类信息,再次检查其他数据表,最终在表relationships中找到了cid对应的mid:

lw8xoz2o.png

​  同样在表metas中能够找到mid对应的类别slug:

lw8xrbje.png

​  因为我的永久链接样式在后台是这样设置的:

lw8xv7h2.png

​  所以我的文章具体链接不能够仅仅只根据文章slug组合出链接,而是还需要在中间加入类别的slug,因此我们在这个方法中加入一个sql查询,根据文章cid查询出文章所在类别的slug,最后再组合:修改代码 $permalink = $item['permalink']; 为以下内容:

$cid = $item['cid'];
// 根据 cid 值查询对应的 mid 值
$mid = $db->fetchRow($db->select('mid')->from('table.relationships')->where('cid = ?', $cid));
// 根据 mid 值查询对应的类别 slug 值
$classSlug = $db->fetchRow($db->select('slug')->from('table.metas')->where('mid = ?', $mid['mid']));
// 构建完整的 URL
$permalink = \Helper::options()->siteUrl.'/'.$classSlug['slug'].'/'.$item['slug'].'.html' ?? '';

​  与之前修改独立页面地址的方法不同的是,在独立页面地址组合的时候我们使用的是 $this 来获取对应属性,但这是个纯PHP函数文件而非主题文件,没有产生 $this 对象,所以不能使用这个方法,在查看其他代码的时候发现可以使用 \Helper::options()->siteUrl; 实现在其他文件中获取,于是就使用这个方案了,保存代码刷新首页,在首页和子类页面中查看热门文章链接均正常,修复完成!

修复“那年今天”模块

  那年今天模块是Joe自带的模块,部分插件/其他模板也会加入这个模块,但代码实现原理可能不相同,所以如果不是Joe主题的这个模块还需要根据具体报错情况分析解决。
  通过观察报错问题,可以发现这次出现了两个问题,一个是和上面一样的permalink无法获取,这里解决方案和第二个修复一样,还有一个问题就是时间日期获取失败,同样是在结构中无定义,问题出在文件/usr/themes/Joe/module/aside.php大概64行的位置

if ($result instanceof Traversable) {
            foreach ($result as $item) {
                $item = Typecho_Widget::widget('Widget_Abstract_Contents')->push($item);
                $historyTodaylist[] = array(
                    "title" => htmlspecialchars($item['title']),
                    "permalink" => $item['permalink'],
                    "date" => $item['year'] . ' ' . $item['month'] . '/' . $item['day']
                );
            }
        }

 因为我们已经知道了在数据表中已经没有了直接的时间记录,而是 created 和 modified 字段,一般将created(发布时间)作为展示的时间,所以获取这个时间戳转换成标准的年月日格式再赋值给data即可:

if ($result instanceof Traversable) {
            foreach ($result as $item) {
                $item = Typecho_Widget::widget('Widget_Abstract_Contents')->push($item);
                $cid = $item['cid'];
                // 根据 cid 值查询对应的 mid 值
                $mid = $db->fetchRow($db->select('mid')->from('table.relationships')->where('cid = ?', $cid));
                // 根据 mid 值查询对应的类别 slug 值
                $classSlug = $db->fetchRow($db->select('slug')->from('table.metas')->where('mid = ?', $mid['mid']));
                // 构建完整的 URL
                $permalink = $this->options->siteUrl.'/'.$classSlug['slug'].'/'.$item['slug'].'.html' ?? '';
                $historyTodaylist[] = array(
                    "title" => htmlspecialchars($item['title']),
                    "permalink" => $permalink,
                    "date" => date('Y-m-d', $item['created'])
                );
            }
        }

最后访问首页/其他页面观察侧边栏的“那年今天”模块,正常显示,修复完成!

其他问题

4

评论 (0)

取消