在移植大叔的 Cherry 主题过程中,发现 WordPress 版本有一项功能是文章内容中插入其他文章的卡片,直接删掉该模块有些可惜,遂研究了下该如何实现,检索后发现已经有短代码插件可以使用,但不太符合需求,所以考虑利用 functions.php
文件来实现,预览效果如下文章卡片。

Typecho 按年输出归档页面这个功能,网上能检索到现成的代码,但对于移植主题复杂的 html 结...
首先得捋清楚需求,在编辑文章过程中,可以通过插入形如 [post id="10"]
这样的短代码,在文章进行解析时,将匹配到的短代码转化为文章卡片,根据图中的内容可以知道,文章卡片中需要调取 ID 为 10 的文章中的文章标题、文章链接、文章摘要、文章缩略图这些字段,直接贴出完成代码。
// 文章短代码
Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = array('ShortcodeParser', 'postCard');
class ShortcodeParser
{
public static function postCard($content, $widget)
{
$pattern = '/\[post\s+id=["\']?(\d+)["\']?\]/i';
return preg_replace_callback($pattern, function($matches) {
return self::buildPostCard($matches[1]);
}, $content);
}
private static function buildPostCard($cid)
{
try {
$db = Typecho_Db::get();
$options = Typecho_Widget::widget('Widget_Options');
$post = $db->fetchRow($db->select('title', 'text', 'slug', 'created', 'modified')
->from('table.contents')
->where('cid = ?', intval($cid))
->where('type = ?', 'post')
->where('status = ?', 'publish')
->limit(1));
if (!$post) return '文章不存在';
// 根据路由配置动态选择生成方式
$routeExists = (bool)Typecho_Router::get('post');
$permalink = $routeExists
? Typecho_Common::url(
Typecho_Router::url(
'post',
[
'slug' => $post['slug'],
'category' => self::getFirstCategory($cid)
]
),
$options->siteUrl
)
: $options->siteUrl . '?cid=' . $cid;
$excerpt = self::getExcerpt($post['text'], 50);
$thumb = $options->Thumb . '?url=' . self::getPostThumb($cid, $options) . '&w=200&h=140';
return <<<HTML
<div class="post_go">
<div class="post_left">
<img decoding="async" src="{$thumb}" alt="{$post['title']}">
<div class="post_info">
<div class="post_name_h2">{$post['title']}</div>
<p>{$excerpt}</p>
</div>
</div>
<a class="post_url" href="{$permalink}">阅读全文
<i class="bi bi-arrow-right ms-2"></i>
</a>
</div>
HTML;
}
catch (Exception $e) {
return '文章加载失败:'.$e->getMessage();
}
}
private static function getFirstCategory($cid)
{
$db = Typecho_Db::get();
return $db->fetchRow($db->select('slug')
->from('table.metas')
->join('table.relationships', 'table.relationships.mid = table.metas.mid')
->where('table.relationships.cid = ?', $cid)
->where('table.metas.type = ?', 'category')
->limit(1))['slug'] ?? '';
}
private static function getExcerpt($text, $length)
{
$cleanText = trim(strip_tags($text));
return Typecho_Common::subStr($cleanText, 0, $length, '...');
}
private static function getPostThumb($cid, $options)
{
$uploadBase = defined('__TYPECHO_UPLOAD_URL__')
? rtrim(__TYPECHO_UPLOAD_URL__, '/')
: $options->siteUrl;
$default = $options->Image ?? '';
$db = Typecho_Db::get();
$attachments = $db->fetchAll($db->select('text')
->from('table.contents')
->where('parent = ?', $cid)
->where('type = ?', 'attachment'));
foreach ($attachments as $attach) {
$meta = unserialize($attach['text']);
if (isset($meta['mime']) && strpos($meta['mime'], 'image/') === 0) {
return Typecho_Common::url($meta['path'], $uploadBase);
}
}
return $default;
}
}
上面是 functions.php
中的代码,将该段代码放入主题的 functions.php 文件中,当文章内容中有类似 [post id="10"]
的内容就会被解析成如下 html 结构。
<div class="post_go">
<div class="post_left">
<img decoding="async" src="{$thumb}" alt="{$post['title']}">
<div class="post_info">
<div class="post_name_h2">{$post['title']}</div>
<p>{$excerpt}</p>
</div>
</div>
<a class="post_url" href="{$widget->permalink}">阅读全文
<i class="bi bi-arrow-right ms-2"></i>
</a>
</div>
注意:在文章缩略图的函数中,因为个人使用的原因,是通过 getPostThumb()
从获取文章第一个图片附件,若附件中无图片则调用主题设置中的 Image 字段设置作为默认缩略图,你可能需要在主题中加入如下配置项。
$Image = new Typecho_Widget_Helper_Form_Element_Text('Image', NULL, NULL, _t('默认缩略图'));
$form->addInput($Image);
实际使用该段代码时,你可能会发现文章列表中使用 <?php $this->excerpt(100, '...'); ?>
输出的摘要部分会存在形如 [post id="10"]
的短代码,如果介意的话可以将下面代码加入 functions.php
中,并在文章列表循环中使用 <?php echo clearExcerpt($this->excerpt); ?>
来输出摘要。
// 摘要过滤
function clearExcerpt($content, $max_length = 150) {
$clean = preg_replace('/\[[^]]+\]/', '', $content);
$clean = strip_tags($clean);
$clean = htmlspecialchars_decode($clean);
$clean = str_replace(['“', '”'], '"', $clean);
$clean = preg_replace('/\s+/', ' ', $clean);
return Typecho_Common::subStr($clean, 0, $max_length, '...');
}
评论(0)