注意:这个是在typecho 1.0版本下测试的,看到typecho 0.9版本也是用的markdown实现,所以理论上typecho 0.9也可以用。

一、思路

先说动机...就是根本搜不到支持typecho 1.0的友情链接插件(实际上我是打算展示自己练手的小项目),所以无奈之下直接看PHP源码自己动手实现了。

实际上就是在后台建立一个独立页面,在独立页面中写链接名并添加链接(平常的markdown)方法;然后编辑主题源码中functions.php,增加正则表达式提取之前独立页面内容的链接名和链接函数,并输出为html元素;最后在主题源码中sidebar.php中增加一个widget,并调用刚才的函数。

效果就像我的博客这样了。

二、新建独立页面并写入内容

新建独立页面

很简单,进入后台,撰写->创建页面

大概像下面:
back.png
注意记住独立页面的自定义url字段,如我的是project

写入内容

内容大概如上图,即首先写名字,然后对其建立链接,需要注意:

  • 此页面中只为sidebar中需要显示的内容建立超级链接,因为后面正则表达式会抓取所有有超级链接的;
  • 后面如[1]: http://xxx/xxx/xx.html中,:后有一个空格,URL最后面必须有空格或回车之类的符号;
  • 强调一下上面的,默认情况下整个独立页面markdown文档最后一个URL后直接是文件结束,此时需要自己在最后再加一个空格或回车符,避免正则表达式对最后一个解析失败

tip:可以用如phpMyAdmin看到实际存储在数据库中独立页面的内容,在表typecho_contentsslug字段值为如我的是project,其text字段值就是markdown内容。

三、编辑正则表达式处理函数

该函数实现最核心的功能,需要写在functions.php中。

直接上代码:

function PageToLinks($slug = 'links')
{
    $db = Typecho_Db::get();
    
    $contents = $db->fetchObject($db->select('text')->from('table.contents')
    ->where('slug = ?', $slug)->limit(1));
    if (!$contents) {
        return;
    }
    $text = $contents->text;
    $titles = $db->fetchObject($db->select('title')->from('table.contents')
    ->where('slug = ?', $slug)->limit(1));
    $title=$titles->title;

    echo "<h3 class='widget-title'>".$title."</h3>";
    echo "<ul class='widget-list'>";
    preg_match_all("/\[(.*?)\]\[(\d)\]/", $text,$r);
    foreach ($r[1] as $key => $value) {
        $num=$r[2][$key];
        preg_match_all("/\[$num\]:\s(.*?)\s/", $text, $urls);
        $href="<a href=".$urls[1][0].">".$value."</a>";
        echo "<li>".$href."</li>";
    }
    echo "</ul>";
}

一个个解释:

$slug = 'links'

即独立页面的slug,如我的是project,不指定的话就是links

$db = Typecho_Db::get();

用来获取数据库支持

$contents = $db->fetchObject($db->select('text')->from('table.contents')
->where('slug = ?', $slug)->limit(1));

在数据库中获取此slug页面内容,此时还不是内容本身

$text = $contents->text;

用来获取内容本身,实际上就是markdown文档

$titles = $db->fetchObject($db->select('title')->from('table.contents')
->where('slug = ?', $slug)->limit(1));
$title=$titles->title;

用来获取此slug页面的标题

echo "<h3 class='widget-title'>".$title."</h3>";
echo "<ul class='widget-list'>";

依照格式输出html格式的标题,和html中list的前缀

preg_match_all("/\[(.*?)\]\[(\d)\]/", $text,$r);

对内容用正则表达式获取链接名,和链接序号,如
Flask设置返回json格式数据 1

$num=$r[2][$key];

取得序号

preg_match_all("/\[$num\]:\s(.*?)\s/", $text, $urls);

对内容用正则表达式,指定特定的需要,找出其链接URL

$href="<a href=".$urls[1][0].">".$value."</a>";

形成html格式的超级链接,$urls[1][0]即URL,$value即链接名

echo "<li>".$href."</li>";

将刚才形成的a标签包裹到li中并输出

echo "</ul>";

最后输出list后缀

注意:

  • 最主要的问题在两个正则表达式中,可以需要根据实际情况修正
  • 因为我好久没有接触php,代码也是匆匆写成,所以一定有更好的代码

四、在sidebar中添加widget并调用函数

关于填充在sidebar的哪个地方,就是看自己的意思了

sidebar由一个或多个section组成,每个section结构大概如下:

<section class="widget">
    <h3 class="widget-title">THE TITLE</h3>
    <ul class="widget-list">
        <li>
            <a href="THE-URL">THE-TITLE</a>
        </li>
    ...
    ...
</section>

之前的函数已经填充了section的内容,所以代码很容易了:

<section class="widget">
    <?php PageToLinks('project'); ?> 
</section>

需要将哪个独立页面内容展示到sidebar,函数参数就填哪个独立页面的slug

五、完成

编辑完成后只需要重新刷新页面就能看到效果了。

六、重新说下注意事项

  • 独立页面内容实际上符合markdown规范就没啥问题,只是需要在最末尾加一个空格或者回车
  • 正则表达式部分正常情况下不需要修改,但也不排除特殊情况
  • sidebar新增的section如果和之前有的,如“最新文章”排版不匹配的话,考虑编辑输出函数,主要应该在html中class上和h3标题标签上。

七、后记

我觉得这样实现是很好的,不需要触及数据库部分,而且函数简单,不需要涉及很多改动,另外也没有什么副作用。

计划将其做成一个插件,不过也只是计划而已...