WordPress’te İçindekiler Tablosu Otomatik Oluşturma: TOC Fonksiyonu
Blog yazılarında içerik ne kadar zengin olursa olsun, okuyucunun o içeriğe ulaşması zorlaşıyorsa tüm emek boşa gidebilir. Uzun WordPress yazılarında, dokümantasyon sayfalarında ya da ürün açıklama metinlerinde kullanıcılar “acaba bu konuya değinilmiş mi?” diye sayfayı yukarı aşağı kaydırıp duruyor. İşte tam bu noktada İçindekiler Tablosu (Table of Contents / TOC) devreye giriyor ve hem kullanıcı deneyimini hem de SEO performansını ciddi biçimde iyileştiriyor.
Bu yazıda WordPress’te functions.php dosyasına ekleyeceğimiz özel PHP fonksiyonlarıyla TOC’u otomatik olarak nasıl oluşturabileceğimizi, özelleştirebileceğimizi ve yönetebileceğimizi ele alacağız. Hazır eklenti kurmak yerine kendi çözümünüzü yazmak isteyenler için oldukça pratik bir rehber olacak.
Neden Hazır Eklenti Değil, functions.php?
“TOC için zaten onlarca eklenti var, neden uğraşayım?” sorusu aklınıza gelebilir. Haklısınız, ancak her eklenti beraberinde bağımlılık, güncelleme derdi ve performans maliyeti getirir. Özellikle hafif bir tema kullanıyorsanız ve sadece TOC işlevine ihtiyacınız varsa, birkaç satır PHP kodu bu sorunu çok daha temiz çözer.
functions.php üzerinden yapılan çözümün avantajları:
- Bağımlılık yok: Eklenti güncellemeleri sitenizi bozmaz
- Tam kontrol: HTML yapısı, CSS sınıfları tamamen sizin elinizde
- Performans: Ekstra JavaScript dosyası veya veritabanı sorgusu yok
- Öğrenme: WordPress filter/action mantığını daha iyi anlarsınız
Temel Mantık Nasıl Çalışır?
TOC oluşturmanın özü şu adımlardan oluşur:
- Post içeriğini alırken
the_contentfiltresini yakala - İçerikteki
,gibi başlık etiketlerini regex ile bul - Her başlığa benzersiz bir
idattribute ekle - Bu başlıkları kullanarak bağlantılı bir liste oluştur
- Listeyi içeriğin başına ya da istediğin bir yere yerleştir
Basit görünüyor, çünkü gerçekten basit. Haydi koda geçelim.
Adım 1: Temel TOC Fonksiyonu
İlk olarak içerikteki başlıkları tespit eden ve onlara id ekleyen temel fonksiyonu yazıyoruz.
// functions.php içine ekleyin
function generate_toc($content) {
// Sadece tekil yazı sayfalarında çalıştır
if (!is_single() && !is_page()) {
return $content;
}
// H2 ve H3 başlıklarını bul
preg_match_all('/<h([2-3])[^>]*>(.*?)</h1>/i', $content, $matches);
// Yeterli başlık yoksa TOC oluşturma
if (count($matches[0]) < 3) {
return $content;
}
$toc = '<div class="toc-container">';
$toc .= '<div class="toc-title">İçindekiler</div>';
$toc .= '<ul class="toc-list">';
$modified_content = $content;
$used_ids = [];
foreach ($matches[0] as $index => $heading) {
$level = $matches[1][$index];
$text = strip_tags($matches[2][$index]);
$anchor = sanitize_title($text);
// Aynı isimde birden fazla başlık varsa sonuna sayı ekle
if (in_array($anchor, $used_ids)) {
$anchor = $anchor . '-' . ($index + 1);
}
$used_ids[] = $anchor;
// Başlığa id ekle
$new_heading = str_replace(
'<h' . $level,
'<h' . $level . ' id="' . $anchor . '"',
$heading
);
$modified_content = str_replace($heading, $new_heading, $modified_content);
// TOC listesine ekle
$indent = ($level == 3) ? ' class="toc-sub"' : '';
$toc .= '<li' . $indent . '><a href="#' . $anchor . '">' . $text . '</a></li>';
}
$toc .= '</ul></div>';
return $toc . $modified_content;
}
add_filter('the_content', 'generate_toc');
Bu fonksiyon çalıştığında her ve etiketine otomatik id atanır ve sayfanın başına linkleri olan bir liste eklenir.
Adım 2: CSS ile Görünümü Güzelleştirme
TOC’un HTML’i hazır, şimdi bunu güzel göstermek için stil eklememiz gerekiyor. Bunu wp_head aksiyonuna bağlayarak yapabiliriz.
function toc_inline_styles() {
echo '<style>
.toc-container {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-left: 4px solid #0073aa;
border-radius: 4px;
padding: 20px 25px;
margin: 30px 0;
max-width: 600px;
}
.toc-title {
font-weight: 700;
font-size: 1.1em;
margin-bottom: 12px;
color: #333;
}
.toc-list {
list-style: none;
padding: 0;
margin: 0;
counter-reset: toc-counter;
}
.toc-list li {
counter-increment: toc-counter;
padding: 4px 0;
border-bottom: 1px dotted #dee2e6;
}
.toc-list li:last-child {
border-bottom: none;
}
.toc-list li::before {
content: counter(toc-counter) ". ";
color: #0073aa;
font-weight: 600;
min-width: 20px;
display: inline-block;
}
.toc-list a {
color: #555;
text-decoration: none;
}
.toc-list a:hover {
color: #0073aa;
text-decoration: underline;
}
.toc-sub {
padding-left: 20px !important;
font-size: 0.9em;
}
.toc-sub::before {
content: "-- " !important;
color: #888 !important;
}
</style>';
}
add_action('wp_head', 'toc_inline_styles');
Adım 3: Belirli Yazı Türlerinde ve Kategorilerde Çalıştırma
Her sayfada TOC istemeyebilirsiniz. Mesela sadece belirli bir kategorideki yazılarda ya da sadece “Rehber” post type’larında göstermek istiyorsunuz. Bunu kontrol eden bir wrapper ekleyelim.
function generate_toc($content) {
// Yalnızca ana sorgu döngüsünde çalış
if (!in_the_loop() || !is_main_query()) {
return $content;
}
// Sadece tekil içeriklerde çalış
if (!is_singular()) {
return $content;
}
// Belirli post type'larda çalıştır
$allowed_post_types = ['post', 'page', 'rehber', 'dokumantasyon'];
if (!in_array(get_post_type(), $allowed_post_types)) {
return $content;
}
// Belirli kategoriyi kontrol et (sadece 'tutorial' kategorisi)
if (is_single() && !has_category('tutorial') && !has_category('rehber')) {
// Bu satırı kaldırırsanız tüm yazılarda çalışır
// return $content;
}
// TOC oluşturma kodunun geri kalanı...
preg_match_all('/<h([2-3])[^>]*>(.*?)</h1>/i', $content, $matches);
if (count($matches[0]) < 3) {
return $content;
}
// Fonksiyonun geri kalanı aynı kalır
return $content; // Placeholder
}
Adım 4: TOC’u Shortcode Olarak Kullanmak
Bazen TOC’u içeriğin başına değil, editörde belirlediğiniz bir yere koymak isteyebilirsiniz. Bunun için shortcode yaklaşımı çok daha esnek olur.
function toc_shortcode_handler($atts) {
global $post;
$atts = shortcode_atts([
'title' => 'İçindekiler',
'min_headers' => 2,
'levels' => '2,3',
], $atts, 'toc');
$content = $post->post_content;
// Shortcode'u içerikten temizle (sonsuz döngü önlemi)
$content = preg_replace('/[toc[^]]*]/', '', $content);
// Seviye konfigürasyonu
$levels = implode('', explode(',', $atts['levels']));
$pattern = '/<h([' . $levels . '])[^>]*>(.*?)</h1>/i';
preg_match_all($pattern, $content, $matches);
if (count($matches[0]) < intval($atts['min_headers'])) {
return '';
}
$toc = '<div class="toc-container toc-shortcode">';
$toc .= '<div class="toc-title">' . esc_html($atts['title']) . '</div>';
$toc .= '<ul class="toc-list">';
$used_ids = [];
foreach ($matches[2] as $index => $text) {
$level = $matches[1][$index];
$clean = strip_tags($text);
$anchor = sanitize_title($clean);
if (in_array($anchor, $used_ids)) {
$anchor .= '-' . ($index + 1);
}
$used_ids[] = $anchor;
$indent = ($level == 3) ? ' class="toc-sub"' : '';
$toc .= '<li' . $indent . '><a href="#' . esc_attr($anchor) . '">' . esc_html($clean) . '</a></li>';
}
$toc .= '</ul></div>';
return $toc;
}
add_shortcode('toc', 'toc_shortcode_handler');
Artık editörde [toc] yazmanız yeterli. Ya da [toc title="Sayfa Haritası" levels="2,3,4"] şeklinde parametreler verebilirsiniz.
Adım 5: Smooth Scroll Ekleme
Kullanıcı TOC’daki bir bağlantıya tıkladığında sayfa aniden zıplamak yerine yumuşakça kayarsa çok daha iyi bir deneyim sunar.
function toc_smooth_scroll_script() {
// Sadece TOC olan sayfalarda yükle
if (!is_singular()) {
return;
}
?>
<script>
document.addEventListener('DOMContentLoaded', function() {
var tocLinks = document.querySelectorAll('.toc-list a');
tocLinks.forEach(function(link) {
link.addEventListener('click', function(e) {
e.preventDefault();
var targetId = this.getAttribute('href').substring(1);
var target = document.getElementById(targetId);
if (target) {
var offset = 80; // Sabit header varsa piksel cinsinden yüksekliği
var targetPos = target.getBoundingClientRect().top + window.pageYOffset - offset;
window.scrollTo({
top: targetPos,
behavior: 'smooth'
});
// URL'yi güncelle ama zıplama
history.pushState(null, null, '#' + targetId);
}
});
});
});
</script>
<?php
}
add_action('wp_footer', 'toc_smooth_scroll_script');
Adım 6: “Başa Dön” Linkleri
Uzun yazılarda her başlığın yanına “Başa Dön” linki eklemek kullanıcı deneyimini iyileştirir. Bu özelliği de the_content filtresiyle otomatik hale getirebiliriz.
function add_back_to_top_links($content) {
if (!is_singular() || !in_the_loop()) {
return $content;
}
// TOC varsa (en az 3 başlık) "başa dön" linklerini ekle
preg_match_all('/<h[2-3][^>]*>/', $content, $check);
if (count($check[0]) < 3) {
return $content;
}
$back_link = ' <a href="#" class="back-to-top" title="Başa Dön" aria-label="Başa Dön">↑</a>';
// Her h2 ve h3 kapanış etiketinden önce link ekle
$content = preg_replace(
'/(</h[2-3]>)/i',
$back_link . '$1',
$content
);
return $content;
}
add_filter('the_content', 'add_back_to_top_links', 20);
Buna karşılık gelen CSS’i de ekleyelim:
function toc_additional_styles() {
echo '<style>
.back-to-top {
font-size: 0.75em;
margin-left: 10px;
color: #aaa;
text-decoration: none;
vertical-align: middle;
transition: color 0.2s;
}
.back-to-top:hover {
color: #0073aa;
}
/* TOC alanını yazdırma görünümünde gizle */
@media print {
.toc-container {
display: none;
}
}
/* Mobil uyumluluk */
@media (max-width: 600px) {
.toc-container {
max-width: 100%;
padding: 15px;
}
}
</style>';
}
add_action('wp_head', 'toc_additional_styles');
Adım 7: Meta Box ile Yazı Bazlı TOC Kontrolü
Bazı yazılarda TOC istemeyebilirsiniz. Her yazı için “TOC’u gizle” seçeneği sunan bir meta box ekleyelim.
// Meta box'ı kaydet
function toc_meta_box_save($post_id) {
if (!isset($_POST['toc_nonce']) || !wp_verify_nonce($_POST['toc_nonce'], 'toc_meta')) {
return;
}
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
if (!current_user_can('edit_post', $post_id)) {
return;
}
$hide_toc = isset($_POST['hide_toc']) ? '1' : '0';
update_post_meta($post_id, '_hide_toc', $hide_toc);
}
add_action('save_post', 'toc_meta_box_save');
// Meta box HTML
function toc_meta_box_html($post) {
$hide = get_post_meta($post->ID, '_hide_toc', true);
wp_nonce_field('toc_meta', 'toc_nonce');
echo '<label>';
echo '<input type="checkbox" name="hide_toc" value="1" ' . checked($hide, '1', false) . '>';
echo ' Bu yazıda İçindekiler Tablosunu gizle';
echo '</label>';
}
// Meta box'ı ekrana getir
function toc_add_meta_box() {
add_meta_box(
'toc_settings',
'TOC Ayarları',
'toc_meta_box_html',
['post', 'page'],
'side',
'default'
);
}
add_action('add_meta_boxes', 'toc_add_meta_box');
Bu meta box’ı generate_toc fonksiyonunuza entegre etmek için fonksiyonun başına şunu ekleyin:
// generate_toc fonksiyonunun içinde, en başa ekleyin:
global $post;
if (get_post_meta($post->ID, '_hide_toc', true) === '1') {
return $content;
}
Gerçek Dünya Senaryosu: WooCommerce Ürün Açıklamaları
WooCommerce kullanıyorsanız uzun ürün açıklamalarında da TOC işinize yarayabilir. Özellikle teknik ürünlerde, “Teknik Özellikler”, “Kurulum”, “Garanti” gibi bölümlere hızlı erişim sağlamak dönüşüm oranlarını artırabilir.
function woo_product_toc($content) {
// Sadece WooCommerce ürün sayfalarında çalış
if (!is_product()) {
return $content;
}
preg_match_all('/<h([2-4])[^>]*>(.*?)</h1>/i', $content, $matches);
if (count($matches[0]) < 2) {
return $content;
}
$toc = '<div class="toc-container toc-product">';
$toc .= '<div class="toc-title">Hızlı Erişim</div>';
$toc .= '<ul class="toc-list">';
$used_ids = [];
foreach ($matches[0] as $index => $heading) {
$level = $matches[1][$index];
$text = strip_tags($matches[2][$index]);
$anchor = sanitize_title($text);
if (in_array($anchor, $used_ids)) {
$anchor .= '-' . ($index + 1);
}
$used_ids[] = $anchor;
$new_heading = str_replace('<h' . $level, '<h' . $level . ' id="' . $anchor . '"', $heading);
$content = str_replace($heading, $new_heading, $content);
$toc .= '<li><a href="#' . esc_attr($anchor) . '">' . esc_html($text) . '</a></li>';
}
$toc .= '</ul></div>';
return $toc . $content;
}
add_filter('the_content', 'woo_product_toc');
SEO Açısından TOC’un Önemi
Google, doğru implement edilmiş TOC’ları arama sonuçlarında sitelink olarak gösterebiliyor. Bu, organik tıklama oranınızı ciddi biçimde artırabilir. Bunun için yapmanız gerekenler:
- Başlıklara verilen
iddeğerlerinin temiz ve anlamlı olması (kisanitize_title()bunu yapıyor) - TOC linklerinin
formatında olması - Sayfa yapısının semantik olması (H1 > H2 > H3 hiyerarşisi)
- Schema markup eklemek isteyenler için
Articleschema içindehasPartözelliği kullanılabilir
Ayrıca çok uzun içeriklerde TOC, kullanıcıların sayfada daha uzun süre kalmasını sağlar. Bu da dolaylı olarak bounce rate’i düşürür ve Google’ın gözünde içeriğin kalitesi hakkında olumlu sinyal verir.
Hata Ayıklama İpuçları
Fonksiyonları ekledikten sonra TOC görünmüyorsa şunları kontrol edin:
is_single()veyais_singular()kontrolü: Yazı arşivlerinde, ana sayfada çalışmaz, bu normal- Minimum başlık sayısı: Kodda
< 3kontrolü var, yazınızda 3’ten az başlık varsa TOC çıkmaz - Tema çakışması: Temanızın
the_contentfiltresini geçersiz kılıp kılmadığınıhas_filter('the_content', 'generate_toc')ile test edin - Cache sorunu: W3 Total Cache veya WP Super Cache kullanıyorsanız önbelleği temizleyin
- HTML yapısı: Editörde başlıkların gerçekten
etiketi olarak kaydedildiğini, özellikle Classic Editor kullanıyorsanız Visual moddan çıkıp Text modda kontrol edin
Sonuç
WordPress functions.php dosyasına birkaç yüz satır kod ekleyerek tam özellikli, özelleştirilebilir ve performanslı bir TOC sistemi kurabilirsiniz. Bu yazıda ele aldığımız yaklaşım size şunları sağladı:
- Otomatik başlık tespiti ve ID atama
- Shortcode desteği ile esnek yerleştirme
- Smooth scroll ile gelişmiş UX
- “Başa Dön” bağlantıları
- Yazı bazlı meta box kontrolü
- WooCommerce ürün uyumluluğu
Bu çözümü kendi projenize göre adapte etmek için önce temel fonksiyonla başlayın, çalıştığını doğrulayın, sonra ihtiyaçlarınıza göre katmanları ekleyin. Hazır eklenti kurup ne yaptığını bilmemek yerine, kendi yazdığınız kodu anlamak ve kontrol etmek uzun vadede çok daha sürdürülebilir bir yaklaşım.
Herhangi bir adımda takılırsanız veya farklı bir post type için uyarlama yapmak isterseniz yorumlarda belirtin, birlikte bakarız.
