在移植大叔的 Cherry 主题过程中,发现 WordPress 版本有一项功能是文章内容中插入其他文章的卡片,直接删掉该模块有些可惜,遂研究了下该如何实现,检索后发现已经有短代码插件可以使用,但不太符合需求,所以考虑利用 functions.php 文件来实现,预览效果如下文章卡片。
[post id=”11”]
首先得捋清楚需求,在编辑文章过程中,可以通过插入形如 [post id=""10""] 这样的短代码,在文章进行解析时,将匹配到的短代码转化为文章卡片,根据图中的内容可以知道,文章卡片中需要调取 ID 为 10 的文章中的文章标题、文章链接、文章摘要、文章缩略图这些字段,直接贴出完成代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
| 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 结构。
1 2 3 4 5 6 7 8 9 10 11 12
| <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 字段设置作为默认缩略图,你可能需要在主题中加入如下配置项。
1 2
| $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); ?> 来输出摘要。
1 2 3 4 5 6 7 8 9 10 11
| 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, '...'); }
|