]*)>(.*?)<\/h\1>/i', $content, $matches, PREG_SET_ORDER); foreach ($matches as $index => $match) { $level = (int) $match[1]; // 2 or 3 $text = strip_tags($match[2]); // Remove any HTML tags inside heading // Generate a clean ID from the heading text $id = roi_generate_heading_id($text, $index); $headings[] = array( 'level' => $level, 'text' => $text, 'id' => $id, ); } return $headings; } /** * Generate a clean ID for a heading * * Creates a URL-friendly ID from heading text. * * @param string $text Heading text * @param int $index Index of the heading (for uniqueness) * @return string Clean ID */ function roi_generate_heading_id($text, $index) { // Remove special characters and convert to lowercase $id = sanitize_title($text); // If ID is empty, use a fallback if (empty($id)) { $id = 'heading-' . $index; } return $id; } /** * Generate HTML for Table of Contents * * Creates a nested list structure from the headings array. * * @param array $headings Array of headings from roi_extract_headings() * @return string HTML for the table of contents */ function roi_generate_toc($headings) { // Get minimum headings required from theme options $min_headings = (int) roi_get_option('toc_min_headings', 2); if (empty($headings) || count($headings) < $min_headings) { return ''; // Don't show TOC if there are fewer headings than required } // Get custom TOC title from theme options $toc_title = roi_get_toc_title(); $toc_html = ''; return $toc_html; } /** * Add IDs to headings in content * * Modifies the post content to add ID attributes to H2 and H3 headings. * * @param string $content Post content * @return string Modified content with IDs added to headings */ function roi_add_heading_ids($content) { if (empty($content)) { return $content; } // Extract headings first to get consistent IDs $headings = roi_extract_headings($content); if (empty($headings)) { return $content; } // Replace headings with versions that include IDs $heading_index = 0; $content = preg_replace_callback( '/]*)>(.*?)<\/h\1>/i', function($matches) use ($headings, &$heading_index) { if (!isset($headings[$heading_index])) { return $matches[0]; } $level = $matches[1]; $text = $matches[2]; $id = $headings[$heading_index]['id']; $heading_index++; return '' . $text . ''; }, $content ); return $content; } /** * Modify post content to add heading IDs * * Filters the_content to add IDs to headings for TOC linking. * * @param string $content Post content * @return string Modified content */ function roi_filter_content_add_heading_ids($content) { // Only apply to single posts if (!is_single()) { return $content; } return roi_add_heading_ids($content); } add_filter('the_content', 'roi_filter_content_add_heading_ids', 10);