给Typecho增加文章置顶功能
AI摘要:文章介绍了如何在Typecho博客中实现文章置顶功能,避免使用插件。作者首先讨论了在主题设置项中添加文章ID的置顶方法,但认为操作繁琐。随后,作者分享了一个自定义字段的无插件置顶方案,通过修改`functions.php`和`index.php`文件,在后台编辑页面添加置顶选项,并在首页优先显示置顶文章。最后,作者提醒置顶文章会占用每页显示数量,建议合理设置。
在逛博客的时候,发现资深网民孙先生写了一篇:Typecho文章置顶(非插件),看了下实现思路发现是在 functions.php
添加主题设置项,然后写完文章之后,在设置项中把文章的id放进去来实现的置顶。
其实这个就是仁者见仁智者见智了,我觉得还是在管理文章的时候,设置比较合适,毕竟不想找文章的id,然后再去主题设置那里去搞,步骤比较繁琐。
Typecho其实是在发布文章时可以添加自定义字段,通过自定义字段去给文章做一些特殊配置是比较合适的,而且这个字段是跟文章保存的,后面导出或者迁移,这些字段也是很方便的备份出来。
于是网上搜索了一番,找到了一篇使用自定义字段无插件实现typecho文章置顶功能,借助AI的能力,让他根据我的主题调整了一下,于是代码如下:
在 functions.php
的最上面添加
// 添加置顶选项确认按钮
Typecho_Plugin::factory('admin/write-post.php')->option = 'addStickyCheckbox';
然后在 functions.php
随便找个位置,插入以下代码:
// 添加文章置顶选项到后台编辑页面
function addStickyCheckbox() {
$post = Typecho_Widget::widget('Widget_Contents_Post_Edit');
// 默认不勾选置顶,只有在明确设置了isSticky=1时才勾选
$isChecked = ($post->fields->isSticky == 1) ? 'checked' : '';
$html = '<section class="typecho-post-option"><label class="typecho-label">文章置顶</label><p><input type="checkbox" id="is_sticky" name="fields[isSticky]" value="1" ' . $isChecked .'> <label for="is_sticky">首页置顶文章</label></p></section>';
$html .= '<script>
document.addEventListener("DOMContentLoaded", function() {
var checkbox = document.getElementById("is_sticky");
var isStickyCustom = document.getElementById("fieldvalue");
// 初始化时设置默认值为0(不置顶)
if (!isStickyCustom.value) {
isStickyCustom.value = "0";
}
checkbox.addEventListener("change", function() {
if (this.checked) {
isStickyCustom.value = "1";
} else {
isStickyCustom.value = "0";
}
});
});
</script>';
echo $html;
}
// 获取所有置顶文章的ID
function getStickyPostIds() {
$db = Typecho_Db::get();
$query = $db->select('cid')
->from('table.fields')
->where('name = ?', 'isSticky')
->where('str_value = ?', '1');
return $db->fetchAll($query, function($row) {
return (int)$row['cid'];
});
}
最麻烦的一步来了,打开 index.php
,这个是负责首页展示的,
我最开始的代码是:
<div class="col-mb-12 col-8" id="main" role="main">
<?php while($this->next()): ?>
<article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<h2 class="post-title" itemprop="name headline"><a itemprop="url" href="<?php $this->permalink() ?>"><?php $this->title() ?></a></h2>
<ul class="post-meta">
<li><time datetime="<?php $this->date('c'); ?>" itemprop="datePublished"><?php $this->date(); ?></time></li>
<li><?php $this->category(','); ?></li>
<li itemprop="interactionCount"><a itemprop="discussionUrl" href="<?php $this->permalink() ?>#comments"><?php $this->commentsNum('抢沙发', '抢板凳', '%d 条评论'); ?></a></li>
<li><?php $this->charactersNum(); ?>字</li>
<li><?php get_post_view($this) ?>次阅读</li>
</ul>
<div class="post-content" itemprop="articleBody">
<?php
$this->content('- 阅读剩余部分 -');
?>
</div>
</article>
<?php endwhile; ?>
<?php $this->pageNav('« 前一页', '后一页 »'); ?>
</div>
然后把这里文章的内容块提取出来,命名为 article.php
调整成这样:
<article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<h2 class="post-title" itemprop="name headline">
<a itemprop="url" href="<?php $post->permalink() ?>"><?php $post->title() ?></a>
<?php if ($isSticky): ?>
<span class="sticky-tag">置顶</span>
<?php endif; ?>
</h2>
<ul class="post-meta">
<li><time datetime="<?php $post->date('c'); ?>" itemprop="datePublished"><?php $post->date(); ?></time></li>
<li><?php $post->category(','); ?></li>
<li itemprop="interactionCount"><a itemprop="discussionUrl" href="<?php $post->permalink() ?>#comments"><?php $post->commentsNum('抢沙发', '抢板凳', '%d 条评论'); ?></a></li>
<li><?php $post->charactersNum(); ?>字</li>
<li><?php get_post_view($post) ?>次阅读</li>
</ul>
<div class="post-content" itemprop="articleBody">
<?php
$post->content('- 阅读剩余部分 -');
?>
</div>
</article>
然后修改 index.php
替换成下面的:
<div class="col-mb-12 col-8" id="main" role="main">
<?php
// 获取所有置顶文章的 CID
$stickyIds = getStickyPostIds();
$stickyPosts = [];
$normalPosts = [];
// 遍历文章,将置顶文章和普通文章分开
while ($this->next()) {
if (in_array($this->cid, $stickyIds)) {
$stickyPosts[] = clone $this; // 置顶文章
} else {
$normalPosts[] = clone $this; // 普通文章
}
}
// 优先显示置顶文章
foreach ($stickyPosts as $post) {
$isSticky = true;
include 'article.php';
}
// 显示普通文章
foreach ($normalPosts as $post) {
$isSticky = false;
include 'article.php';
}
?>
<?php $this->pageNav('« 前一页', '后一页 »'); ?>
</div>
我把无关的代码都去掉,就能看明白了吧,区分开然后分别循环!
然后再打开文章编辑器,右侧就出现了下图:
这样再发布文章或者编辑文章的时候,就能够自己动手勾选一下就完事了。
不过,这里需要注意的是,置顶文章会占用每页显示文章的数量,例如我每页设置 10 篇,如果置顶了 2 篇,那么非置顶的文章只能显示 8 篇。所以,在置顶的时候要最好不要超过设置的文章数量。
上面的代码如果实在是看不明白的话,可以让AI按照这个例子改就可以,现在AI还是比较厉害的。
目前主题基本上完善了常用的功能,下次把 Typecho 切换暗色和亮色这个功能分享出来,主题折腾的也就告一段落了。
我用的也是通过文章ID来实现置顶的插件,ID的话还好,我文章链接用的/{cid}.html,一眼就能看出来ID是多少 ꈍ◡ꈍ
看来用文章ID的还是比较多,最近在研究Typecho,发现官方给的自定义字段挺好用的,而且也是推荐使用自定义字段来扩展模板功能,后面准备再深入研究研究看看能把模块弄的个性一点。