wordpress 手动添加文章目录(原创)

问题描述

wordpress 添加文章目录已经有很成熟的方案,无论是通过插件还是通过手动添加代码的方式,但是这些方式都是在文章内容中插入文章目录,而我希望将文章目录单独列到原本属于 widget 的侧边栏中。所以我打算通过借鉴上面两种方式,来实现自己的文章目录。

借鉴手动方式

手动方式重点是向 theme 的functions.php 中添加 add_filter( "the_content", "article_index" );
他将使用函数article_index给文章内容进行过滤。在functions.php中再定义一个function article_index($content)接受文章内容作为参数,返回被过滤后的文章内容(添加了文章目录的内容),文章目录就被插入了。
以下是网络上找到的内容

function article_index($content) {
    $matches = array();
    $ul_li = '';
    $r = "/<h3>([^<]+)</h3>/im";
    if(preg_match_all($r, $content, $matches)) {
        foreach($matches[1] as $num => $title) {
            $content = str_replace($matches[0][$num], '<h3 id="title-'.$num.'">'.$title.'</h3>', $content);
            $ul_li .= '<li><a href="#title-'.$num.'" title="'.$title.'">'.$title."</a></li>n";
        }
        $content = "n<div id="article-index">
                <strong>文章目录</strong>
                <ul id="index-ul">n" . $ul_li . "</ul>
            </div>n" . $content;
    }
    return $content;
}

缺点是正则匹配太局限,不支持多级目录。

借鉴插件方式

选择的插件是:Content Index for wordpress
安装后发现功能是我想要的,有多级目录。实现功能的代码是 wp-content/plugins/wp-content-index.php
关键的函数是content_index_analysis但是研究了老半天依然没有理清楚他的逻辑。不过里面找到一个正则$r = "/<h(\d)([^>]*)>(.*)<\/h\d>/isU";他可以匹配所有的<h>标签。

思路

要让 single.php 侧边栏输出文章目录,只要在 single.php 中调用一个定义在 functions.php 中的函数,而该函数负责输出一串包含文章目录的html代码片段就好了。难点是如何输出这些片段。
问题抽象一下后,会发现是这样的,如何让下面这样一组数据组织成树状结构。

[0] h1
[1] h2
[2] h2
[3] h3
[4] h4
[5] h2

他应该被组织成这样

[0] h1
   [1] h2
   [2] h2
      [3] h3
         [4] h4
   [5] h2

在做这个练习的时候,我发现我依靠了 h 本身的位置和层级

代码

function article_index($content) {
    $matches = array();
    $r = "/<h(\d)([^>]*)>(.*)<\/h\d>/isU";
    if (is_single() && preg_match_all($r, $content, $matches, PREG_SET_ORDER)) {
        $arr = article_index_create($matches);
        $ul_li = article_index_ul($arr);
        $side = '<div class="col-md-4"><div id="secondary" class="widget-area content-index" role="complementary">'
                .'<nav class="bs-docs-sidebar hidden-print hidden-xs hidden-sm affix">'.$ul_li.'</nav></div></div>';
        echo $side;
    }
}

function article_index_create($arr) {
    $arr_wash = array();
    $min_level = $arr[0][1];
    $max_level = $min_level;
    foreach ($arr as $key => $value) {
        preg_match("/id=\"(.*)\"/", $value[2], $href);
        $title = trim(strip_tags($value[0]));
        $arr_wash[] = ['href'=> $href[1] , 'title' => $title, 'level'=> $value[1]];
        if ($min_level > $value[1]) {
            $min_level =  $value[1];
        }
        if ($max_level < $value[1]) {
            $max_level = $value[1];
        }
    }    
    foreach ($arr_wash as $key => $value) {
        if ($value['level'] == $min_level) {
            $arr_wash[$key]['father'] = $key;
        } else {
            $father = null;
            for ($i = ($key - 1); $i >= 0; $i-- ) {
                if ($arr_wash[$i]['level'] < $value['level']) {
                    $father = $i;
                    break;
                }
            }
            if (is_null($father)) {
                unset($arr_wash[$key]);
            } else {
                $arr_wash[$key]['father'] = $father;
            }
        }
    }
    for ($i = $max_level; $i > $min_level; $i--) {
        foreach ($arr_wash as $key => $value) {
            if ($value['level'] == $i) {
                $arr_wash[$value['father']]['child'][$key] = $value;
                unset($arr_wash[$key]);    
            }
        }
    }
    return $arr_wash;
}

function article_index_ul($arr_wash) {
    $ul_li = '<ul>';
    foreach ($arr_wash as $key => $val) {
        $ul_li .= ul_recursion($val);
    }
    $ul_li .= '</ul>';
    return $ul_li;
}

function ul_recursion($val)
{
    if (! $val['child']) {
        return '<li><a href="#'.$val['href'].'">'.$val['title'].'</a></li>';
    } else {
        $ul_li .= '<li><a href="#'.$val['href'].'">'.$val['title'].'</a><ul>';
        foreach ($val['child'] as $k => $v) {
            $ul_li .= ul_recursion($v);
        }
        $ul_li .= '</ul></li>';
        return $ul_li;
    }
}

稍作解释

article_index_create是最主要的,他将调用其它函数来完成生成文章目录的功能。
article_index_create他将接受匹配到的标题,返回包含层级关系的数组。
article_index_ul 负责将包含层级关系的数组转换成ul字符串。
ul_recursion用到了递归来处理子级。

总结

算法比具体的实现要费脑子 >”<||||

欢迎点评!

One comment

发表评论

电子邮件地址不会被公开。 必填项已用*标注