[handsome]让引用其他文章使用自定义摘要

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]

最后修改:2020 年 06 月 08 日 03 : 23 PM
欢迎投食喵 ~

发表评论

3 条评论

  1. Ryan

    调用内置的filter转换一下不香吗

    $db->fetachObject($select, array('Widget_Abstract_Contents', 'filter'));
    1. 无限UCW
      @Ryan

      自定义字段在设计上就是不应用 fliter 的。

  2. 周易测算网

    谢谢分享,日常打卡~ 滴滴~୧(๑•̀⌄•́๑)૭