| @@ -2,16 +2,16 @@ | ||
| 2 | 2 | |
| 3 | 3 | /** |
| 4 | 4 | * Plugin Name: SimpleTOC - Table of Contents Block |
| 5 | 5 | * Plugin URI: https://marc.tv/simpletoc-wordpress-inhaltsverzeichnis-plugin-gutenberg/ |
| 6 | - * Description: Adds a basic "Table of Contents" Gutenberg block. | |
| 7 | - * Version: 5.0.3 | |
| 6 | + * Description: SEO-friendly Table of Contents Gutenberg block. No JavaScript and no CSS means faster loading. | |
| 7 | + * Version: 5.0.29 | |
| 8 | 8 | * Author: Marc Tönsing |
| 9 | 9 | * Author URI: https://marc.tv |
| 10 | 10 | * Text Domain: simpletoc |
| 11 | 11 | * License: GPL v2 or later |
| 12 | 12 | * License URI: http://www.gnu.org/licenses/gpl-2.0.html |
| 13 | - * | |
| 13 | + * | |
| 14 | 14 | */ |
| 15 | 15 | |
| 16 | 16 | /** |
| 17 | 17 | * Initalise frontend and backend and register block |
| @@ -23,10 +23,10 @@ | ||
| 23 | 23 | wp_set_script_translations( 'simpletoc-toc-editor-script', 'simpletoc' ); |
| 24 | 24 | |
| 25 | 25 | add_filter('plugin_row_meta', __NAMESPACE__ . '\\simpletoc_plugin_meta', 10, 2); |
| 26 | 26 | |
| 27 | - register_block_type( __DIR__ . '/build' , [ | |
| 28 | - 'render_callback' => __NAMESPACE__ . '\\render_callback' | |
| 27 | + register_block_type( __DIR__ . '/build', [ | |
| 28 | + 'render_callback' => __NAMESPACE__ . '\\render_callback_simpletoc' | |
| 29 | 29 | ]); |
| 30 | 30 | |
| 31 | 31 | } |
| 32 | 32 | |
| @@ -32,8 +32,79 @@ | ||
| 32 | 32 | |
| 33 | 33 | add_action( 'init', 'register_simpletoc_block' ); |
| 34 | 34 | |
| 35 | 35 | /** |
| 36 | + * Inject potentially missing translations into the block-editor i18n | |
| 37 | + * collection. | |
| 38 | + * | |
| 39 | + * This keeps the plugin backwards compatible, in case the user did not | |
| 40 | + * update translations on their website (yet). | |
| 41 | + * | |
| 42 | + * @param string|false|null $translations JSON-encoded translation data. Default null. | |
| 43 | + * @param string|false $file Path to the translation file to load. False if there isn't one. | |
| 44 | + * @param string $handle Name of the script to register a translation domain to. | |
| 45 | + * @param string $domain The text domain. | |
| 46 | + * | |
| 47 | + * @return string|false|null JSON string | |
| 48 | + */ | |
| 49 | +add_filter( 'load_script_translations', function($translations, $file, $handle, $domain) { | |
| 50 | + if ( 'simpletoc' === $domain && $translations ) { | |
| 51 | + // List of translations that we inject into the block-editor JS. | |
| 52 | + $dynamic_translations = [ | |
| 53 | + 'Table of Contents' => __( 'Table of Contents', 'simpletoc' ), | |
| 54 | + ]; | |
| 55 | + | |
| 56 | + $changed = false; | |
| 57 | + $obj = json_decode( $translations, true ); | |
| 58 | + | |
| 59 | + // Confirm that the translation JSON is valid. | |
| 60 | + if ( isset( $obj['locale_data'] ) && isset( $obj['locale_data']['messages'] ) ) { | |
| 61 | + $messages = $obj['locale_data']['messages']; | |
| 62 | + | |
| 63 | + // Inject dynamic translations, when needed. | |
| 64 | + foreach ( $dynamic_translations as $key => $locale ) { | |
| 65 | + if ( | |
| 66 | + empty( $messages[ $key ] ) | |
| 67 | + || ! is_array( $messages[$key] ) | |
| 68 | + || ! array_key_exists( 0, $messages[ $key ] ) | |
| 69 | + || $locale !== $messages[ $key ][0] | |
| 70 | + ) { | |
| 71 | + $messages[ $key ] = [ $locale ]; | |
| 72 | + $changed = true; | |
| 73 | + } | |
| 74 | + } | |
| 75 | + | |
| 76 | + // Only modify the translations string when locales did change. | |
| 77 | + if ( $changed ) { | |
| 78 | + $obj['locale_data']['messages'] = $messages; | |
| 79 | + $translations = wp_json_encode( $obj ); | |
| 80 | + } | |
| 81 | + } | |
| 82 | + } | |
| 83 | + | |
| 84 | + return $translations; | |
| 85 | +}, 10, 4 ); | |
| 86 | + | |
| 87 | +/** | |
| 88 | + * Sets the default value of translatable attributes. | |
| 89 | + * | |
| 90 | + * Values inside block.json are static strings that are not translated. This | |
| 91 | + * filter inserts relevant translations i | |
| 92 | + * | |
| 93 | + * @param array $settings Array of determined settings for registering a block type. | |
| 94 | + * @param array $metadata Metadata provided for registering a block type. | |
| 95 | + * | |
| 96 | + * @return array Modified settings array. | |
| 97 | + */ | |
| 98 | +add_filter( 'block_type_metadata_settings', function( $settings, $metadata ) { | |
| 99 | + if ( 'simpletoc/toc' === $metadata['name'] ) { | |
| 100 | + $settings['attributes']['title_text']['default'] = __( 'Table of Contents', 'simpletoc' ); | |
| 101 | + } | |
| 102 | + | |
| 103 | + return $settings; | |
| 104 | +}, 10, 2); | |
| 105 | + | |
| 106 | +/** | |
| 36 | 107 | * Filter to add plugins to the TOC list for Rank Math plugin |
| 37 | 108 | * |
| 38 | 109 | * @param array TOC plugins. |
| 39 | 110 | */ |
| @@ -42,18 +113,55 @@ | ||
| 42 | 113 | $toc_plugins['simpletoc/plugin.php'] = 'SimpleTOC'; |
| 43 | 114 | return $toc_plugins; |
| 44 | 115 | }); |
| 45 | 116 | |
| 117 | +add_filter( 'the_content', 'simpletoc_addIDstoContent', 1 ); | |
| 118 | + | |
| 119 | +function simpletoc_addIDstoContent( $content ) { | |
| 120 | + | |
| 121 | + $blocks = parse_blocks( $content ); | |
| 122 | + | |
| 123 | + $blocks = addIDstoBlocks_recursive( $blocks ); | |
| 124 | + | |
| 125 | + $content = serialize_blocks( $blocks ); | |
| 126 | + | |
| 127 | + return $content; | |
| 128 | +} | |
| 129 | + | |
| 130 | +function addIDstoBlocks_recursive( $blocks ) { | |
| 131 | + | |
| 132 | + foreach ( $blocks as &$block ) { | |
| 133 | + if (isset($block['blockName']) && ( $block['blockName'] === 'core/heading' || $block['blockName'] === 'generateblocks/headline') && isset($block['innerHTML']) && isset($block['innerContent']) && isset($block['innerContent'][0]) ){ | |
| 134 | + $block['innerHTML'] = addAnchorAttribute($block['innerHTML']); | |
| 135 | + $block['innerContent'][0] = addAnchorAttribute($block['innerContent'][0]); | |
| 136 | + } else if( isset($block['attrs']['ref']) ){ | |
| 137 | + // search in reusable blocks (this is not finished because I ran out of ideas.) | |
| 138 | + // $reusable_block_id = $block['attrs']['ref']; | |
| 139 | + // $reusable_block_content = parse_blocks(get_post($reusable_block_id)->post_content); | |
| 140 | + } else if ( ! empty( $block['innerBlocks'] ) ) { | |
| 141 | + // search in groups | |
| 142 | + $block['innerBlocks'] = addIDstoBlocks_recursive( $block['innerBlocks'] ); | |
| 143 | + } | |
| 144 | + } | |
| 145 | + | |
| 146 | + return $blocks; | |
| 147 | +} | |
| 148 | + | |
| 46 | 149 | /** |
| 47 | - * Render block output | |
| 150 | + * Render block output | |
| 48 | 151 | * |
| 49 | 152 | */ |
| 50 | 153 | |
| 51 | -function render_callback( $attributes ) | |
| 154 | +function render_callback_simpletoc( $attributes ) | |
| 52 | 155 | { |
| 53 | - //add only if block is used in this post. | |
| 54 | - add_filter('render_block', __NAMESPACE__ . '\\filter_block', 10, 2); | |
| 55 | 156 | |
| 157 | + $is_backend = defined('REST_REQUEST') && true === REST_REQUEST && 'edit' === filter_input(INPUT_GET, 'context'); | |
| 158 | + | |
| 159 | + $title_text = esc_html( trim( $attributes['title_text'] ) ); | |
| 160 | + if ( ! $title_text ) { | |
| 161 | + $title_text = __('Table of Contents', 'simpletoc'); | |
| 162 | + } | |
| 163 | + | |
| 56 | 164 | $alignclass = ''; |
| 57 | 165 | if ( isset ($attributes['align']) ) { |
| 58 | 166 | $align = $attributes['align']; |
| 59 | 167 | $alignclass = 'align' . $align; |
| @@ -60,53 +168,108 @@ | ||
| 60 | 168 | } |
| 61 | 169 | |
| 62 | 170 | $className = ''; |
| 63 | 171 | if ( isset( $attributes['className'] ) ) { |
| 64 | - $className = strip_tags(htmlspecialchars($attributes['className'])); | |
| 172 | + $className = strip_tags(htmlspecialchars($attributes['className'] )); | |
| 65 | 173 | } |
| 66 | 174 | |
| 175 | + $pre_html = ''; | |
| 176 | + $post_html = ''; | |
| 177 | + if ( $className != '' ) { | |
| 178 | + $pre_html = '<div class="simpletoc ' . $className . '">'; | |
| 179 | + $post_html = '</div>'; | |
| 180 | + } | |
| 181 | + | |
| 67 | 182 | $post = get_post(); |
| 68 | - $blocks = parse_blocks($post->post_content); | |
| 183 | + if ( is_null($post) || is_null($post->post_content) ) { | |
| 184 | + $blocks = ''; | |
| 185 | + } else { | |
| 186 | + $blocks = parse_blocks($post->post_content); | |
| 187 | + } | |
| 69 | 188 | |
| 70 | - if (empty($blocks)) { | |
| 189 | + if ( empty($blocks) ) { | |
| 71 | 190 | $html = ''; |
| 72 | - if ($attributes['no_title'] == false) { | |
| 73 | - $html = '<h2 class="simpletoc-title">' . __('Table of Contents2', 'simpletoc') . '</h2>'; | |
| 191 | + if( $is_backend == true ) { | |
| 192 | + if ($attributes['no_title'] == false) { | |
| 193 | + $html = '<h2 class="simpletoc-title ' . $alignclass . '">' . $title_text . '</h2>'; | |
| 194 | + } | |
| 195 | + | |
| 196 | + $html .= '<p class="components-notice is-warning ' . $alignclass . '">' . __('No blocks found.', 'simpletoc') . ' ' . __('Save or update post first.', 'simpletoc') . '</p>'; | |
| 74 | 197 | } |
| 75 | - $html .= '<p class="components-notice is-warning ' . $alignclass . '">' . __('No blocks found.', 'simpletoc') . ' ' . __('Save or update post first.', 'simpletoc') . '</p>'; | |
| 76 | 198 | return $html; |
| 77 | 199 | } |
| 78 | 200 | |
| 79 | 201 | $headings = array_reverse(filter_headings_recursive($blocks)); |
| 80 | 202 | |
| 203 | + // enrich headings with pages as a data-attribute | |
| 204 | + $headings = simpletoc_add_pagenumber($blocks, $headings); | |
| 205 | + | |
| 81 | 206 | $headings_clean = array_map('trim', $headings); |
| 82 | 207 | |
| 83 | - if (empty($headings_clean)) { | |
| 208 | + if ( empty( $headings_clean ) ) { | |
| 84 | 209 | $html = ''; |
| 85 | - if ($attributes['no_title'] == false) { | |
| 86 | - $html = '<h2 class="simpletoc-title">' . __('Table of Contents', 'simpletoc') . '</h2>'; | |
| 210 | + if( $is_backend == true ) { | |
| 211 | + | |
| 212 | + if ($attributes['no_title'] == false) { | |
| 213 | + $html = '<h2 class="simpletoc-title ' . $alignclass . '">' . $title_text . '</h2>'; | |
| 214 | + } | |
| 215 | + | |
| 216 | + $html .= '<p class="components-notice is-warning ' . $alignclass . '">' . __('No headings found.', 'simpletoc') . ' ' . __('Save or update post first.', 'simpletoc') . '</p>'; | |
| 87 | 217 | } |
| 88 | - $html .= '<p class="components-notice is-warning ' . $alignclass . '">' . __('No headings found.', 'simpletoc') . ' ' . __('Save or update post first.', 'simpletoc') . '</p>'; | |
| 89 | 218 | return $html; |
| 90 | 219 | } |
| 91 | 220 | |
| 92 | - $output = generateToc($headings_clean, $attributes); | |
| 221 | + $toclist = generateToc($headings_clean, $attributes); | |
| 93 | 222 | |
| 94 | - $pre_html = '<div class="simpletoc ' . $className . ' ' . $alignclass . '">'; | |
| 95 | - $post_html = '</div>'; | |
| 96 | - $output = $pre_html . $output . $post_html; | |
| 223 | + if ( empty( $toclist ) ) { | |
| 224 | + $html = ''; | |
| 225 | + if( $is_backend == true ) { | |
| 97 | 226 | |
| 227 | + if ($attributes['no_title'] == false) { | |
| 228 | + $html = '<h2 class="simpletoc-title ' . $alignclass . '">' . $title_text . '</h2>'; | |
| 229 | + } | |
| 230 | + | |
| 231 | + $html .= '<p class="components-notice is-warning ' . $alignclass . '">' . __('No headings found.', 'simpletoc') . ' ' . __('Check minimal and maximum level block settings.', 'simpletoc') . '</p>'; | |
| 232 | + } | |
| 233 | + return $html; | |
| 234 | + | |
| 235 | + } | |
| 236 | + | |
| 237 | + $output = $pre_html . $toclist . $post_html; | |
| 238 | + | |
| 98 | 239 | return $output; |
| 99 | 240 | } |
| 100 | 241 | |
| 242 | + | |
| 243 | +function simpletoc_add_pagenumber( $blocks, $headings ){ | |
| 244 | + $pages = 1; | |
| 245 | + | |
| 246 | + foreach ($blocks as $block => $innerBlock) { | |
| 247 | + | |
| 248 | + // count nextpage blocks | |
| 249 | + if (isset($blocks[$block]['blockName']) && $blocks[$block]['blockName'] === 'core/nextpage' ){ | |
| 250 | + $pages++; | |
| 251 | + } | |
| 252 | + | |
| 253 | + if (isset($blocks[$block]['blockName']) && $blocks[$block]["blockName"] === 'core/heading') { | |
| 254 | + // make sure its a headline. | |
| 255 | + foreach ($headings as $heading => &$innerHeading){ | |
| 256 | + if($innerHeading == $blocks[$block]["innerHTML"]){ | |
| 257 | + $innerHeading = preg_replace("/(<h1|<h2|<h3|<h4|<h5|<h6)/i", '$1 data-page="' . $pages . '"', $blocks[$block]["innerHTML"]); | |
| 258 | + } | |
| 259 | + } | |
| 260 | + } | |
| 261 | + } | |
| 262 | + return $headings; | |
| 263 | +} | |
| 264 | + | |
| 101 | 265 | /** |
| 102 | - * Return all headings with a recursive walk through all blocks. | |
| 103 | - * This includes groups and reusable block with groups within reusable blocks. | |
| 266 | + * Return all headings with a recursive walk through all blocks. | |
| 267 | + * This includes groups and reusable block with groups within reusable blocks. | |
| 104 | 268 | */ |
| 105 | 269 | |
| 106 | -function filter_headings_recursive($blocks) | |
| 270 | +function filter_headings_recursive( $blocks ) | |
| 107 | 271 | { |
| 108 | - | |
| 109 | 272 | $arr = array(); |
| 110 | 273 | |
| 111 | 274 | foreach ($blocks as $block => $innerBlock) { |
| 112 | 275 | |
| @@ -121,27 +284,34 @@ | ||
| 121 | 284 | $arr = array_merge(filter_headings_recursive($innerBlock), $arr); |
| 122 | 285 | } |
| 123 | 286 | } else { |
| 124 | 287 | |
| 125 | - if (isset($blocks['blockName']) && $blocks['blockName'] === 'core/heading' && $innerBlock !== 'core/heading') { | |
| 288 | + if (isset($blocks['blockName']) && ( $blocks['blockName'] === 'core/heading' ) && $innerBlock !== 'core/heading') { | |
| 126 | 289 | // make sure its a headline. |
| 127 | 290 | if (preg_match("/(<h1|<h2|<h3|<h4|<h5|<h6)/i", $innerBlock)) { |
| 128 | 291 | $arr[] = $innerBlock; |
| 129 | 292 | } |
| 130 | 293 | } |
| 294 | + | |
| 295 | + if (isset($blocks['blockName']) && ( $blocks['blockName'] === 'generateblocks/headline' ) && $innerBlock !== 'core/heading') { | |
| 296 | + // make sure its a headline. | |
| 297 | + if (preg_match("/(<h1|<h2|<h3|<h4|<h5|<h6)/i", $innerBlock)) { | |
| 298 | + $arr[] = $innerBlock; | |
| 299 | + } | |
| 300 | + } | |
| 131 | 301 | } |
| 132 | 302 | } |
| 133 | 303 | |
| 134 | 304 | return $arr; |
| 305 | + | |
| 135 | 306 | } |
| 136 | 307 | |
| 137 | 308 | /** |
| 138 | - * Remove all problematic characters for toc links | |
| 309 | + * Remove all problematic characters for toc links | |
| 139 | 310 | */ |
| 140 | 311 | |
| 141 | -function simpletoc_sanitize_string($string) | |
| 312 | +function simpletoc_sanitize_string( $string ) | |
| 142 | 313 | { |
| 143 | - | |
| 144 | 314 | // remove punctuation |
| 145 | 315 | $zero_punctuation = preg_replace("/\p{P}/u", "", $string); |
| 146 | 316 | // remove non-breaking spaces |
| 147 | 317 | $html_wo_nbs = str_replace(" ", " ", $zero_punctuation); |
| @@ -150,13 +320,12 @@ | ||
| 150 | 320 | // Sanitizes a title, replacing whitespace and a few other characters with dashes. |
| 151 | 321 | $sanitized_string = sanitize_title_with_dashes($string_without_accents); |
| 152 | 322 | // Encode for use in an url |
| 153 | 323 | $urlencoded = urlencode($sanitized_string); |
| 154 | - | |
| 155 | 324 | return $urlencoded; |
| 156 | 325 | } |
| 157 | 326 | |
| 158 | -function simpletoc_plugin_meta($links, $file) | |
| 327 | +function simpletoc_plugin_meta( $links, $file ) | |
| 159 | 328 | { |
| 160 | 329 | |
| 161 | 330 | if (false !== strpos($file, 'simpletoc')) { |
| 162 | 331 | $links = array_merge($links, array('<a href="https://wordpress.org/support/plugin/simpletoc">' . __('Support', 'simpletoc') . '</a>')); |
| @@ -166,15 +335,15 @@ | ||
| 166 | 335 | |
| 167 | 336 | return $links; |
| 168 | 337 | } |
| 169 | 338 | |
| 170 | -function addAnchorAttribute($html) | |
| 339 | +function addAnchorAttribute( $html ) | |
| 171 | 340 | { |
| 172 | 341 | |
| 173 | 342 | // remove non-breaking space entites from input HTML |
| 174 | 343 | $html_wo_nbs = str_replace(" ", " ", $html); |
| 175 | 344 | |
| 176 | - // Thank you Nick Diego | |
| 345 | + // Thank you Nick Diego | |
| 177 | 346 | if (!$html_wo_nbs) { |
| 178 | 347 | return $html; |
| 179 | 348 | } |
| 180 | 349 | |
| @@ -187,9 +356,10 @@ | ||
| 187 | 356 | $tags = $xpath->evaluate("//*[self::h1 or self::h2 or self::h3 or self::h4 or self::h5 or self::h6]"); |
| 188 | 357 | |
| 189 | 358 | // Loop through all the found tags |
| 190 | 359 | foreach ($tags as $tag) { |
| 191 | - | |
| 360 | + // if tag already has an attribute "id" defined, no need for creating a new one | |
| 361 | + if (!empty($tag->getAttribute('id'))) {continue;} | |
| 192 | 362 | // Set id attribute |
| 193 | 363 | $heading_text = strip_tags($html); |
| 194 | 364 | $anchor = simpletoc_sanitize_string($heading_text); |
| 195 | 365 | $tag->setAttribute("id", $anchor); |
| @@ -200,24 +370,11 @@ | ||
| 200 | 370 | |
| 201 | 371 | return $content; |
| 202 | 372 | } |
| 203 | 373 | |
| 204 | -function filter_block($block_content, $block) | |
| 374 | +function generateToc( $headings, $attributes ) | |
| 205 | 375 | { |
| 206 | - $className = ''; | |
| 207 | 376 | |
| 208 | - if ($block['blockName'] !== 'core/heading') { | |
| 209 | - return $block_content; | |
| 210 | - } | |
| 211 | - | |
| 212 | - $block_content = addAnchorAttribute($block_content); | |
| 213 | - | |
| 214 | - return $block_content; | |
| 215 | -} | |
| 216 | - | |
| 217 | -function generateToc($headings, $attributes) | |
| 218 | -{ | |
| 219 | - | |
| 220 | 377 | $list = ''; |
| 221 | 378 | $html = ''; |
| 222 | 379 | $min_depth = 6; |
| 223 | 380 | $listtype = 'ul'; |
| @@ -225,12 +382,23 @@ | ||
| 225 | 382 | $inital_depth = 6; |
| 226 | 383 | $link_class = ''; |
| 227 | 384 | $styles = ''; |
| 228 | 385 | |
| 386 | + $title_text = esc_html( trim( $attributes['title_text'] ) ); | |
| 387 | + if ( ! $title_text ) { | |
| 388 | + $title_text = __('Table of Contents', 'simpletoc'); | |
| 389 | + } | |
| 390 | + | |
| 391 | + $alignclass = ''; | |
| 392 | + if ( isset ($attributes['align']) ) { | |
| 393 | + $align = $attributes['align']; | |
| 394 | + $alignclass = 'align' . $align; | |
| 395 | + } | |
| 396 | + | |
| 229 | 397 | if ($attributes['remove_indent'] == true) { |
| 230 | 398 | $styles = 'style="padding-left:0;list-style:none;"'; |
| 231 | 399 | } |
| 232 | - | |
| 400 | + | |
| 233 | 401 | if ($attributes['add_smooth'] == true) { |
| 234 | 402 | $link_class = 'class="smooth-scroll"'; |
| 235 | 403 | } |
| 236 | 404 | |
| @@ -249,12 +417,35 @@ | ||
| 249 | 417 | $inital_depth = $min_depth; |
| 250 | 418 | } |
| 251 | 419 | } |
| 252 | 420 | |
| 421 | + /* If there is a custom min level, make sure it is the baseline. */ | |
| 422 | + if ($attributes['min_level'] > $min_depth) { | |
| 423 | + $min_depth = $attributes['min_level']; | |
| 424 | + } | |
| 425 | + | |
| 426 | + $itemcount = 0; | |
| 427 | + | |
| 253 | 428 | foreach ($headings as $line => $headline) { |
| 254 | 429 | |
| 255 | 430 | $title = strip_tags($headline); |
| 431 | + $page = ''; | |
| 432 | + $dom = new \DOMDocument(); | |
| 433 | + @$dom->loadHTML($headline, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); | |
| 434 | + $xpath = new \DOMXPath($dom); | |
| 435 | + $nodes = $xpath->query('//*/@data-page'); | |
| 436 | + | |
| 437 | + if ( isset($nodes[0] ) && $nodes[0]->nodeValue > 1) { | |
| 438 | + $page = $nodes[0]->nodeValue . '/'; | |
| 439 | + $absolute_url = get_permalink(); | |
| 440 | + } | |
| 441 | + | |
| 256 | 442 | $link = simpletoc_sanitize_string($title); |
| 443 | + if (isset($nodes[0]) && !empty($nodes[0]->ownerElement->getAttribute('id'))) { | |
| 444 | + // if the node already has an attribute id, use that as anchor | |
| 445 | + $link = $nodes[0]->ownerElement->getAttribute('id'); | |
| 446 | + } | |
| 447 | + | |
| 257 | 448 | $this_depth = (int) $headings[$line][2]; |
| 258 | 449 | if (isset($headings[$line + 1][2])) { |
| 259 | 450 | $next_depth = (int) $headings[$line + 1][2]; |
| 260 | 451 | } else { |
| @@ -265,9 +456,16 @@ | ||
| 265 | 456 | if ($this_depth > $attributes['max_level'] or strpos($headline, 'class="simpletoc-hidden') > 0) { |
| 266 | 457 | goto closelist; |
| 267 | 458 | } |
| 268 | 459 | |
| 269 | - // start list | |
| 460 | + // skip this heading because a min depth is set. | |
| 461 | + if( $this_depth < $attributes['min_level'] ){ | |
| 462 | + continue; | |
| 463 | + } | |
| 464 | + | |
| 465 | + $itemcount++; | |
| 466 | + | |
| 467 | + // start list | |
| 270 | 468 | if ($this_depth == $min_depth) { |
| 271 | 469 | $list .= "<li>\n"; |
| 272 | 470 | } else { |
| 273 | 471 | // we are not as base level. Start opening levels until base is reached. |
| @@ -275,15 +473,15 @@ | ||
| 275 | 473 | $list .= "\n\t\t<" . $listtype . "><li>\n"; |
| 276 | 474 | } |
| 277 | 475 | } |
| 278 | 476 | |
| 279 | - $list .= "<a " . $link_class . " href=\"" . $absolute_url . "#" . $link . "\">" . $title . "</a>"; | |
| 477 | + $list .= "<a " . $link_class . " href=\"" . $absolute_url . esc_html($page) . "#" . $link . "\">" . $title . "</a>"; | |
| 280 | 478 | |
| 281 | 479 | closelist: |
| 282 | 480 | // close lists |
| 283 | 481 | // check if this is not the last heading |
| 284 | 482 | if ($line != count($headings) - 1) { |
| 285 | - // do we need to close the door behind us? | |
| 483 | + // do we need to close the door behind us? | |
| 286 | 484 | if ($min_depth > $next_depth) { |
| 287 | 485 | // If yes, how many times? |
| 288 | 486 | for ($min_depth; $min_depth > $next_depth; $min_depth--) { |
| 289 | 487 | $list .= "</li></" . $listtype . ">\n"; |
| @@ -300,10 +498,14 @@ | ||
| 300 | 498 | } |
| 301 | 499 | } |
| 302 | 500 | |
| 303 | 501 | if ($attributes['no_title'] == false) { |
| 304 | - $html = "<h2 class=\"simpletoc-title\">" . __("Table of Contents", "simpletoc") . "</h2>"; | |
| 502 | + $html = "<h2 class=\"simpletoc-title\">" . $title_text . "</h2>"; | |
| 305 | 503 | } |
| 306 | - $html .= "<" . $listtype . " class=\"simpletoc-list\" " . $styles .">\n" . $list . "</li></" . $listtype . ">"; | |
| 504 | + $html .= "<" . $listtype . " class=\"simpletoc-list\" " . $styles ." " . $alignclass .">\n" . $list . "</li></" . $listtype . ">"; | |
| 505 | + | |
| 506 | + if($itemcount < 1) { | |
| 507 | + $html = ''; | |
| 508 | + } | |
| 307 | 509 | |
| 308 | 510 | return $html; |
| 309 | 511 | } |