handsome 主题自带“引用其他文章”和“手动指定摘要内容”功能,但两者似乎并不适配。笔者个人认为“手动指定摘要内容”功能更应该交由插件实现(挂 excerpt
钩子),但这超出了本文讨论范围,不详细展开。直接在文章中插入“引用其他文章”的代码,会解析出文章原本的内容并截取作为引用块的摘要,感觉有些不协调。
笔者出于强迫症,考虑从代码层面一次性根本解决这个问题。定位到“引用其他文章”功能实现的核心方法 Content::quoteOtherPostCallback()
(libs/Content.php
),代码就不贴了,可以看到此处是没有被引用文章的上下文的,为了获取文章的信息需要执行 SQL 进行查询。这里作者虽然查了头图字段,但是却并没有查自定义摘要字段。
这里贴一个小技巧(来自 Typecho 源代码),如何优雅地根据 cid 查询自定义字段:
首先肯定是要查一次字段表的,也就是 prefix_fields
表,这里的 prefix_
是安装时设置的数据表前缀。第一个问题就是如何获取这个前缀,但实际上 Typecho 包装的数据库驱动可以使用 table.xxx
代替 prefix_xxx
,那么就不再需要手动获取这个前缀,即:
$db->fetchAll($db->select()->from('table.fields')->where('cid = ?', $cid));
这样一句话将会返回 $cid
文章的所有字段,但是这还不够,对其进行一下加工:
$fields = array();
$rows = $db->fetchAll($db->select()->from('table.fields')->where('cid = ?', $cid));
foreach ($rows as $row) {
$fields[$row['name']] = $row[$row['type'] . '_value'];
}
$fields = new Typecho_Config($fields);
这样处理之后得到的 $fields
(显而易见,是一个 Typecho_Config
对象)对应的成员就保存着对应自定义字段的值。例如 $fields->xxx
。
回到手动指定摘要,该字段对应的内部名称为 customSummary
,这时我们就用 $fields->customSummary
来访问它。
if (trim($fields->customSummary) != "") {
$targetSummary = $fields->customSummary;
} else {
$targetSummary = Content::excerpt(Markdown::convert($result['text']), 60);
}
那么修改后的完整代码就是这样:
/**
* 一篇文章中引用另一篇文章正则替换回调函数
* @param $matches
* @return bool|string
*/
public static function quoteOtherPostCallback($matches){
$options = mget();
// 不解析类似 [post] 双重括号的代码
if ( $matches[1] == '[' && $matches[6] == ']' ) {
return substr($matches[0], 1, -1);
}
//对$matches[3]的url如果被解析器解析成链接,这些需要反解析回来
$matches[3] = preg_replace("/<a href=.*?>(.*?)<\/a>/",'$1',$matches[3]);
$attr = htmlspecialchars_decode($matches[3]);//还原转义前的参数列表
$attrs = self::shortcode_parse_atts($attr);//获取短代码的参数
//这里需要对id做一个判断,避免空值出现错误
$cid = @$attrs["cid"];
$url = @$attrs['url'];
$cover = @$attrs['cover'];//封面
$targetTitle = "";//标题
$targetUrl = "";//链接
$targetSummary ="";//简介文字
$targetImgSrc = "";//封面图片地址
if (!empty($cid)){
$db = Typecho_Db::get();
$prefix = $db->getPrefix();
$posts = $db->fetchAll($db
->select()->from($prefix.'contents')
->orWhere('cid = ?',$cid)
->where('type = ? AND status = ? AND password IS NULL', 'post', 'publish'));
//这里需要对id正确性进行一个判断,避免查找文章失败
if (count($posts) == 0){
$targetTitle = "文章不存在,或文章是加密、私密文章";
}else{
$result = Typecho_Widget::widget('Widget_Abstract_Contents')->push($posts[0]);
$fields = array();
$rows = $db->fetchAll($db->select()->from('table.fields')->where('cid = ?', $cid));
foreach ($rows as $row) {
$fields[$row['name']] = $row[$row['type'] . '_value'];
}
$fields = new Typecho_Config($fields);
if ($cover == "") {
$targetImgSrc = Content:: whenSwitchHeaderImgSrc(0, 2, null, $result['text'], @$fields->thumb, 1);
} else {
$targetImgSrc = $cover;
}
if (trim($fields->customSummary) != "") {
$targetSummary = $fields->customSummary;
} else {
$targetSummary = Content::excerpt(Markdown::convert($result['text']), 60);
}
$targetTitle = $result['title'];
$targetUrl = $result['permalink'];
}
}else if (empty($cid) && $url !=""){
$targetUrl = $url;
$targetSummary = @$attrs['intro'];
$targetTitle = @$attrs['title'];
$targetImgSrc = $cover;
}else{
$targetTitle = "文章不存在,请检查文章CID";
}
$imageHtml = "";
$noImageCss = "";
if (trim($targetImgSrc) != ""){
$imageHtml = '<div class="inner-image bg" style="background-image: url('.$targetImgSrc.');background-size: cover;"></div>
';
}else{
$noImageCss = 'style="margin-left: 10px;"';
}
return <<<EOF
<div class="preview">
<div class="post-inser post">
<a href="{$targetUrl}" target="_blank" class="post_inser_a ">
{$imageHtml}
<div class="inner-content" $noImageCss>
<p class="inser-title">{$targetTitle}</p>
<div class="inster-summary">
{$targetSummary}
</div>
</div>
</a>
<!-- .inner-content #####-->
</div>
<!-- .post-inser ####-->
</div>
EOF;
}
因为本来就进行了一次对字段表的 SQL 查询,修改也只是对其逻辑进行合并,SQL 查询的次数并没有增加。[heimu](其实如果算期望,还是增加了的,原本可能只执行一次,取决于 cover 参数设置与否,现在必然执行两次)[/heimu]
版权声明:本文是原创文章,版权归 无限UCW 所有。
本文链接:https://ucw.moe/archives/use-custom-excerpt-when-quoting.html
本站所有原创文章采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。
您可以自由地转载和修改,但请务必注明文章来源并且不可用于商业目的。
调用内置的filter转换一下不香吗
自定义字段在设计上就是不应用
fliter
的。谢谢分享,日常打卡~ 滴滴~୧(๑•̀⌄•́๑)૭