AI摘要

这段内容介绍了在Typecho主题中实现文章置顶功能的过程。先在 index.php 添加 $this->sticky(); ,又给出置顶功能的代码。还将其集成到主题配置,在 functions.php 创建后台设置选项存储置顶文章cid,解决了前台显示时因逗号导致少显示文章的问题,最终完美实现不依赖插件的置顶功能。

此内容由AI生成,仅用于文章内容的总结

初步思路

初步思路里,除了添加$this->sticky();,其他的忽视即可,可以直接移步到下一个标题,将置顶功能植入主题后台设置,完整的代码和步骤都在下一个标题。不能说这个初步思路错,只能说有更好的更完善的!

在 index.php 的 $this->title(); 前面加上 $this->sticky();例如下面这段代码

<h2 class="title"><a href="<?php $this->permalink() ?>"><?php $this->sticky(); $this->title() ?></a></h2>
//其实就是这个
<?php $this->sticky(); $this->title() ?>

然后下面代码放在主题首页index.php中:

/** 文章置顶 */
$sticky = '1'; //置顶的文章id,多个用|隔开
if($sticky){
    $sticky_cids = explode('|',$sticky); //分割文本
    $sticky_html = "<span style='color:red'>[置顶] </span>"; //置顶标题的 html
    $db = Typecho_Db::get();
    $pageSize = $this->options->pageSize;
    $select1 = $this->select()->where('type = ?', 'post');
    $select2 = $this->select()->where('type = ? && status = ? && created < ?', 'post','publish',time());
    //清空原有文章的列队
    $this->row = [];
    $this->stack = [];
    $this->length = 0;
    $order = '';
    foreach($sticky_cids as $i => $cid) {
        if($i == 0) $select1->where('cid = ?', $cid);
        else $select1->orWhere('cid = ?', $cid);
        $order .= " when $cid then $i";
        $select2->where('table.contents.cid != ?', $cid); //避免重复
    }
    if ($order) $select1->order(null,"(case cid$order end)"); //置顶文章的顺序 按 $sticky 中 文章ID顺序
    if ($this->_currentPage == 1) foreach($db->fetchAll($select1) as $sticky_post){ //首页第一页才显示
        $sticky_post['sticky'] = $sticky_html;
        $this->push($sticky_post); //压入列队
    }
    $uid = $this->user->uid; //登录时,显示用户各自的私密文章
    if($uid) $select2->orWhere('authorId = ? && status = ?',$uid,'private');
    $sticky_posts = $db->fetchAll($select2->order('table.contents.created', Typecho_Db::SORT_DESC)->page($this->_currentPage, $this->parameter->pageSize));
    foreach($sticky_posts as $sticky_post) $this->push($sticky_post); //压入列队
    $this->setTotal($this->getTotal()-count($sticky_cids)); //置顶文章不计算在所有文章内
}

当然,你也可以集成到你的主题配置里,实现后台填写置顶cid,然后前台显示。

创建后台设置选项:

在主题的 functions.php 文件中添加代码,创建一个新的后台设置选项来存储置顶文章的 cid 

// 在主题的 functions.php 文件中
$stickyCids = new Typecho_Widget_Helper_Form_Element_Text('stickyCids', NULL, NULL, _t('置顶文章CID'), _t('在这里填入置顶文章CID,支持多填,用英文逗号隔开'));
$form->addInput($stickyCids);
$stickyCids->setAttribute('class', 'j-setting-content j-setting-global');

前台index.php添加

就当我以为一切顺利大功告成的时候,直接给我整无语了:
置顶一直显示少一个,经过多次折腾分析,发现就是逗号出了问题。按理说最后一个数字后边是不需要加逗号的,但是 69,63,59, 这样才会显示完整的3个,但是后台去掉最后一个逗号的话,比如 69,63,59 这样就只会显示69和63两个。

那我们可以在代码中对分割后的数组进行进一步的检查和处理,确保无论末尾是否有逗号,都能正确获取所有的cid。
下面是我修改完善后的代码,放进index.php即可,配合上边后台设置的语句

<?php
$stickyCids = $this->options->stickyCids;
if ($stickyCids) {
    // 用英文逗号分割
    $sticky_cids = explode(',', $stickyCids);
    // 去除每个元素的空格并过滤掉空元素
    $sticky_cids = array_filter(array_map('trim', $sticky_cids), 'trim');
    $sticky_html = "<span style='color:red'>[置顶] </span>";
    $db = Typecho_Db::get();
    $pageSize = $this->options->pageSize;
    $select1 = $this->select()->where('type =?', 'post');
    $select2 = $this->select()->where('type =? && status =? && created <?', 'post', 'publish', time());
    $this->row = [];
    $this->stack = [];
    $this->length = 0;
    $order = '';
    $stickyCidMap = [];
    $whereClauses = [];
    $whereParams = [];
    foreach ($sticky_cids as $i => $cid) {
        $whereClauses[] = 'cid =?';
        $whereParams[] = $cid;
        $order.= " when ". $cid. " then ". $i;
        $select2->where('table.contents.cid!=?', $cid);
        $stickyCidMap[$cid] = $i;
    }
    if (!empty($whereClauses)) {
        $select1->where(implode(' OR ', $whereClauses),...$whereParams);
    }
    if (empty(trim($order))) {
        $orderBy = 'table.contents.created';
        $sort = Typecho_Db::SORT_DESC;
    } else {
        $orderBy = null;
        $sort = "(case cid$order end)";
    }
    if ($orderBy!== null) {
        $select1->order($orderBy, $sort);
    }
    if ($this->_currentPage == 1) {
        $stickyPosts = $db->fetchAll($select1);
        // 对获取到的置顶文章按照设置的顺序排序
        usort($stickyPosts, function ($a, $b) use ($stickyCidMap) {
            return $stickyCidMap[$a['cid']] - $stickyCidMap[$b['cid']];
        });
        foreach ($stickyPosts as $sticky_post) {
            $sticky_post['sticky'] = $sticky_html;
            $this->push($sticky_post);
        }
    }
    $uid = $this->user->uid;
    if ($uid) {
        $select2->orWhere('authorId =? && status =?', $uid, 'private');
    }
    $sticky_posts = $db->fetchAll($select2->order('table.contents.created', Typecho_Db::SORT_DESC)->page($this->_currentPage, $this->parameter->pageSize));
    foreach ($sticky_posts as $sticky_post) {
        $this->push($sticky_post);
    }
    $this->setTotal($this->getTotal() - count($sticky_cids));
}
?>

由此,不依赖插件并且植入主题设置的置顶文章功能就完美实现了。或许这就是编程的乐趣吧,编写代码,发现问题,然后不断尝试去解决问题,最后守得云开见月明!