PluginProbe
WPJAM Basic / trunk
WPJAM Basic vtrunk
wpjam-basic / extends / wpjam-toc.php

wpjam-toc.php in WPJAM Basic trunk, at extends/wpjam-toc.php

138 lines 4.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Name: 文章目录
4 URI: https://mp.weixin.qq.com/s/vgNtvc1RcWyVCmnQdxAV0A
5 Description: 自动根据文章�
6 容里的子标题提取出文章目录,并显示在�
7 容前。
8 Version: 3.0
9 */
10 class WPJAM_Toc{
11 public static function __callStatic($method, $args){
12 return wpjam_call_option(static::class, $method, ...$args);
13 }
14
15 public static function get_fields(){
16 return [
17 'individual'=> ['title'=>'单独设置', 'type'=>'checkbox', 'value'=>1, 'label'=>'文章列表和编辑页面可以单独设置是否显示文章目录以及显示到第几级。'],
18 'depth' => ['title'=>'显示层级', 'type'=>'select', 'value'=>6, 'options'=> wpjam_fill(range(2, 6), fn($v)=> 'H'.$v)],
19 'position' => ['title'=>'显示位置', 'type'=>'select', 'value'=>'content', 'options'=>['content'=>'显示在文章�
20 容前面', 'shortcode'=>'使用[toc]插�
21 ��
22 容中', 'function'=>'显示在侧边栏/调用函数<code>wpjam_get_toc()</code>显示']],
23 ]+(current_theme_supports('style', 'toc') ? [] : [
24 'css' => ['title'=>'显示样式', 'type'=>'textarea', 'description'=>'也可以将相�
25 �的样式代码复制主题的对应文件中,点击这里获取<a href="https://blog.wpjam.com/m/toc-js-css-code/" target="_blank">文章目录的默认的 CSS</a>']
26 ]);
27 }
28
29 public static function output($wrap=true){
30 $toc = is_singular() ? (string)self::get_arg('toc') : '';
31
32 return $toc && $wrap ? '<details id="toc" open>'."\n".'<summary>文章目录</summary>'."\n".$toc.'</details>'."\n" : $toc;
33 }
34
35 public static function filter_content($content){
36 $depth = self::get_setting('individual', 1) ? (int)get_post_meta(get_the_ID(), 'toc_depth', true) : 0;
37 $depth = $depth ?: self::get_setting('depth', 6);
38
39 if($depth && $depth != -1){
40 $i = 0;
41 $stack = [];
42 $output = $toc = '';
43 $index = str_contains($content, '[toc]');
44 $tag = $index ? 'ol' : 'ul';
45 $parts = preg_split('#(<h([1-'.$depth.'])\b([^>]*)>(.*?)</h\2>)#is', $content, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
46
47 while($i < count($parts)){
48 $part = $parts[$i];
49
50 if(str_starts_with($part, '<h') && $part[2] >= 1 && $part[2] <= $depth){
51 $level = (int)$parts[$i+1];
52 $attr = $parts[$i+2] ? shortcode_parse_atts($parts[$i+2]) : [];
53
54 if(!str_contains($attr['class'] ?? '', 'toc-noindex')){
55 if(empty($attr['id'])){
56 $attr['id'] = 'toc_'.($i+1);
57 }
58
59 if($stack){
60 if($level > array_last($stack)){
61 $toc .= "\n<".$tag.">\n";
62 $output .= $index ? '<section class="section">'."\n" : '';
63 }else{
64 while($level <= array_last($stack)){
65 $toc .= "</li>\n";
66
67 if($level < array_pop($stack)){
68 $toc .= "</".$tag.">\n";
69 $output .= $index ? "</section>\n" : '';
70 }
71 }
72 }
73 }
74
75 $stack[] = $level;
76 $toc .= '<li><a href="#'.$attr['id'].'">'.trim(strip_tags($parts[$i+3])).'</a>';
77 }
78
79 $output .= wpjam_tag('h'.$level, $attr, $parts[$i+3]);
80 $i += 4;
81 }else{
82 $output .= $part;
83 $i += 1;
84 }
85 }
86
87 if($stack){
88 $content = implode([
89 !$index && self::get_setting('position', 'content') == 'content' ? '[toc]' : '',
90 $output,
91 $index ? str_repeat("</section>\n", count($stack)-1) : ''
92 ]);
93
94 self::update_arg('toc', "<".$tag.">\n".$toc.str_repeat("</li>\n</".$tag.">\n", count($stack)));
95 }
96 }
97
98 return str_replace('[toc]', self::output(), $content);
99 }
100
101 public static function add_hooks(){
102 wpjam_register_widget('wpjam-toc', 'WPJAM - 文章目录', [
103 'classname' => 'widget_toc',
104 'fields' => ['title' => ['type'=>'text', 'before'=>'列表标题:', 'class'=>'medium-text']],
105 'widget' => fn()=> self::output(false)
106 ]);
107
108 wpjam_once('maybe', 'the_content', fn($content)=> !doing_filter('get_the_excerpt') && wpjam_is('single', get_the_ID()) ? self::filter_content($content) : null, 11);
109
110 if($css = self::get_setting('css')){
111 wpjam_hook('wp_head', fn()=> is_singular() && !current_theme_supports('style', 'toc') && wpjam_echo('<style type="text/css">'."\n".$css."\n".'</style>'));
112 }
113
114 self::get_setting('individual', 1) && wpjam_register_post_option('wpjam-toc', [
115 'title' => '文章目录',
116 'context' => 'side',
117 'list_table' => true,
118 'post_type' => fn($type)=> is_post_type_viewable($type) && post_type_supports($type, 'editor'),
119 'fields' => ['toc_depth' => [
120 'title' => '层级:',
121 'type' => 'select',
122 'show_in_rest' => ['type'=>'integer'],
123 'default' => 0,
124 'options' => [0=>'默认']+wpjam_fill(range(2, 6), fn($v)=> 'H'.$v)+[-1=>'不显示']
125 ]]
126 ]);
127 }
128 }
129
130 wpjam_register_option('wpjam-toc', [
131 'model' => 'WPJAM_Toc',
132 'title' => '文章目录',
133 'menu_page' => ['tab_slug'=>'toc', 'plugin_page'=>'wpjam-posts', 'summary'=> __FILE__]
134 ]);
135
136 function wpjam_get_toc(){
137 return WPJAM_Toc::output();
138 }