__NAMESPACE__ . '\\render_callback' ]); } add_action( 'init', 'register_simpletoc_block' ); /** * Filter to add plugins to the TOC list for Rank Math plugin * * @param array TOC plugins. */ add_filter('rank_math/researches/toc_plugins', function ($toc_plugins) { $toc_plugins['simpletoc/plugin.php'] = 'SimpleTOC'; return $toc_plugins; }); /** * Render block output * */ function render_callback( $attributes ) { //add only if block is used in this post. add_filter('render_block', __NAMESPACE__ . '\\filter_block', 10, 2); $alignclass = ''; if ( isset ($attributes['align']) ) { $align = $attributes['align']; $alignclass = 'align' . $align; } $className = ''; if ( isset( $attributes['className'] ) ) { $className = strip_tags(htmlspecialchars($attributes['className'])); } $post = get_post(); $blocks = parse_blocks($post->post_content); if (empty($blocks)) { $html = ''; if ($attributes['no_title'] == false) { $html = '

' . __('Table of Contents2', 'simpletoc') . '

'; } $html .= '

' . __('No blocks found.', 'simpletoc') . ' ' . __('Save or update post first.', 'simpletoc') . '

'; return $html; } $headings = array_reverse(filter_headings_recursive($blocks)); $headings_clean = array_map('trim', $headings); if (empty($headings_clean)) { $html = ''; if ($attributes['no_title'] == false) { $html = '

' . __('Table of Contents', 'simpletoc') . '

'; } $html .= '

' . __('No headings found.', 'simpletoc') . ' ' . __('Save or update post first.', 'simpletoc') . '

'; return $html; } $output = generateToc($headings_clean, $attributes); $pre_html = '
'; $post_html = '
'; $output = $pre_html . $output . $post_html; return $output; } /** * Return all headings with a recursive walk through all blocks. * This includes groups and reusable block with groups within reusable blocks. */ function filter_headings_recursive($blocks) { $arr = array(); foreach ($blocks as $block => $innerBlock) { if (is_array($innerBlock)) { if (isset($innerBlock['attrs']['ref'])) { // search in reusable blocks $e_arr = parse_blocks(get_post($innerBlock['attrs']['ref'])->post_content); $arr = array_merge(filter_headings_recursive($e_arr), $arr); } else { // search in groups $arr = array_merge(filter_headings_recursive($innerBlock), $arr); } } else { if (isset($blocks['blockName']) && $blocks['blockName'] === 'core/heading' && $innerBlock !== 'core/heading') { // make sure its a headline. if (preg_match("/(' . __('Support', 'simpletoc') . '')); $links = array_merge($links, array('' . __('Donate', 'simpletoc') . '')); $links = array_merge($links, array('' . __('Write a review', 'simpletoc') . ' ⭐️⭐️⭐️⭐️⭐️')); } return $links; } function addAnchorAttribute($html) { // remove non-breaking space entites from input HTML $html_wo_nbs = str_replace(" ", " ", $html); // Thank you Nick Diego if (!$html_wo_nbs) { return $html; } libxml_use_internal_errors(TRUE); $dom = new \DOMDocument(); @$dom->loadHTML($html_wo_nbs, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); // use xpath to select the Heading html tags. $xpath = new \DOMXPath($dom); $tags = $xpath->evaluate("//*[self::h1 or self::h2 or self::h3 or self::h4 or self::h5 or self::h6]"); // Loop through all the found tags foreach ($tags as $tag) { // Set id attribute $heading_text = strip_tags($html); $anchor = simpletoc_sanitize_string($heading_text); $tag->setAttribute("id", $anchor); } // Save the HTML changes $content = utf8_decode($dom->saveHTML($dom->documentElement)); return $content; } function filter_block($block_content, $block) { $className = ''; if ($block['blockName'] !== 'core/heading') { return $block_content; } $block_content = addAnchorAttribute($block_content); return $block_content; } function generateToc($headings, $attributes) { $list = ''; $html = ''; $min_depth = 6; $listtype = 'ul'; $absolute_url = ''; $inital_depth = 6; $link_class = ''; $styles = ''; if ($attributes['remove_indent'] == true) { $styles = 'style="padding-left:0;list-style:none;"'; } if ($attributes['add_smooth'] == true) { $link_class = 'class="smooth-scroll"'; } if ($attributes['use_ol'] == true) { $listtype = 'ol'; } if ($attributes['use_absolute_urls'] == true) { $absolute_url = get_permalink(); } foreach ($headings as $line => $headline) { if ($min_depth > $headings[$line][2]) { // search for lowest level $min_depth = (int) $headings[$line][2]; $inital_depth = $min_depth; } } foreach ($headings as $line => $headline) { $title = strip_tags($headline); $link = simpletoc_sanitize_string($title); $this_depth = (int) $headings[$line][2]; if (isset($headings[$line + 1][2])) { $next_depth = (int) $headings[$line + 1][2]; } else { $next_depth = ''; } // skip this heading because a max depth is set. if ($this_depth > $attributes['max_level'] or strpos($headline, 'class="simpletoc-hidden') > 0) { goto closelist; } // start list if ($this_depth == $min_depth) { $list .= "
  • \n"; } else { // we are not as base level. Start opening levels until base is reached. for ($min_depth; $min_depth < $this_depth; $min_depth++) { $list .= "\n\t\t<" . $listtype . ">
  • \n"; } } $list .= "" . $title . ""; closelist: // close lists // check if this is not the last heading if ($line != count($headings) - 1) { // do we need to close the door behind us? if ($min_depth > $next_depth) { // If yes, how many times? for ($min_depth; $min_depth > $next_depth; $min_depth--) { $list .= "
  • \n"; } } if ($min_depth == $next_depth) { $list .= ""; } // last heading } else { for ($inital_depth; $inital_depth < $this_depth; $inital_depth++) { $list .= "\n"; } } } if ($attributes['no_title'] == false) { $html = "

    " . __("Table of Contents", "simpletoc") . "

    "; } $html .= "<" . $listtype . " class=\"simpletoc-list\" " . $styles .">\n" . $list . ""; return $html; }