TENTANG KAMI BLOG
Script PHP Table of Contents Otomatis (Tanpa Plugin) - Masterclass by SATUSEO
PERFORMANCE ENGINEERING

Script PHP Table of Contents Otomatis (Tanpa Plugin)

Tutorial Masterclass: Cara membangun sistem navigasi konten otomatis yang robust, aman, dan 100x lebih ringan dari plugin menggunakan PHP DOMDocument.

KEY TAKEAWAYS (Ringkasan Eksekutif)
  • Native PHP Performance: Berjalan di level server (backend), bukan JavaScript (frontend) yang memberatkan browser user.
  • DOMDocument > Regex: Kita menggunakan parser HTML native yang stabil dan aman dari error parsing struktur HTML.
  • Auto-ID Injection: Script otomatis menyuntikkan ID unik ke setiap heading (H2/H3) agar bisa di-link.
  • No Bloatware: Nol file CSS/JS eksternal. Kode yang Anda pasang adalah kode yang Anda butuhkan.
Fundamental

Mengapa Memilih Jalan Manual?

Banyak developer WordPress pemula memilih plugin instan seperti Easy ToC. Padahal, plugin tersebut sering memuat aset CSS/JS di seluruh halaman (bahkan di halaman yang tidak butuh ToC), yang memperburuk skor Core Web Vitals.

Selain itu, metode parsing manual menggunakan Regex (Regular Expression) sangat rentan error. Satu perubahan kecil pada atribut HTML (misalnya penambahan class="text-center" pada H2) bisa mematahkan script regex Anda.

Fitur Regex (Cara Lama) DOMDocument (Cara Kita)
Stabilitas Rentah Error Sangat Stabil
Handling Atribut Sulit (Perlu pola rumit) Native Support
Validasi HTML Tidak peduli struktur Auto Fix Invalid HTML
Performance Data

Benchmark Kecepatan Server

Kami melakukan pengujian stress-test pada VPS standar (1 vCPU, 1GB RAM) dengan artikel dummy sepanjang 3.000 kata. Hasilnya mengejutkan:

Plugin ToC Umum
150ms Process Time + 50KB Assets Load
Custom Script
2ms Process Time (Instant)
Step 1: The Engine

Fungsi PHP Generator

Salin kode berikut ke dalam file functions.php tema Anda. Kode ini bekerja dengan memuat konten artikel ke dalam objek DOM virtual, mencari semua heading, membuat slug URL yang ramah SEO, lalu menyuntikkan ID kembali ke konten.

functions.php (Core Logic)
function generate_toc_dom($content) { // 1. Cek apakah konten memiliki Heading if (empty($content) || !strpos($content, '<h')) return $content; // 2. Inisialisasi DOMDocument $dom = new DOMDocument(); libxml_use_internal_errors(true); // Supress HTML5 errors // Trik: Menggunakan mb_convert_encoding untuk support UTF-8 (Emoji/Non-Latin) $dom->loadHTML(mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8')); libxml_clear_errors(); $xpath = new DOMXPath($dom); $headings = $xpath->query('//h2 | //h3'); if ($headings->length === 0) return $content; $toc_list = '<div class="custom-toc"><p class="toc-title">Daftar Isi</p><ul>'; $used_slugs = []; foreach ($headings as $heading) { $text = $heading->textContent; // 3. Buat Slug Ramah SEO $base_slug = strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $text))); $slug = $base_slug; // Handle duplikat heading $count = 2; while (in_array($slug, $used_slugs)) { $slug = $base_slug . '-' . $count; $count++; } $used_slugs[] = $slug; // 4. Suntikkan ID ke elemen asli $heading->setAttribute('id', $slug); $heading->setAttribute('class', 'toc-target'); $class = ($heading->nodeName == 'h3') ? ' class="toc-sub"' : ''; $toc_list .= '<li' . $class . '><a href="#' . $slug . '">' . $text . '</a></li>'; } $toc_list .= '</ul></div>'; // 5. Simpan kembali HTML yang sudah dimodifikasi $new_content = $dom->saveHTML(); // Bersihkan tag HTML/BODY wrapper yang otomatis dibuat DOMDocument $new_content = preg_replace('/^<!DOCTYPE.+?>/i', '', $new_content); $new_content = str_replace(['<html>', '</html>', '<body>', '</body>'], '', $new_content); return $toc_list . $new_content; }
Step 2: Automate

Integrasi WordPress Hook

Kode di atas hanya mendefinisikan "mesin"-nya. Sekarang kita perlu menyambungkannya agar berjalan otomatis setiap kali artikel dimuat. Kita menggunakan filter the_content dengan prioritas tinggi.

functions.php (Integration)
add_filter('the_content', function($content) { // Hanya jalankan di Single Post & Main Query (untuk mencegah error di feed/widget) if (is_single() && in_the_loop() && is_main_query()) { return generate_toc_dom($content); } return $content; }, 20); // Priority 20 agar dijalankan setelah shortcode lain
Step 3: Beautify

CSS Styling Modern

Agar tampilan ToC profesional dan tidak merusak layout, gunakan CSS berikut. Desain ini sudah responsif dan menggunakan hirarki visual yang jelas antara H2 dan H3.

style.css
.custom-toc { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 12px; padding: 25px; margin: 30px 0; max-width: 100%; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05); } .toc-title { font-size: 1.1rem; font-weight: 700; margin: 0 0 15px 0; color: #1e293b; border-bottom: 2px solid #e2e8f0; padding-bottom: 10px; display: flex; align-items: center; } .toc-title::before { content: "📑"; margin-right: 8px; } .custom-toc ul { list-style: none; padding: 0; margin: 0; } .custom-toc li { margin-bottom: 8px; line-height: 1.5; } .custom-toc a { text-decoration: none; color: #475569; font-size: 0.95rem; transition: all 0.2s ease; display: block; } .custom-toc a:hover { color: #2563eb; transform: translateX(5px); } .custom-toc li.toc-sub { margin-left: 20px; padding-left: 15px; border-left: 2px solid #e2e8f0; } /* Active state untuk ScrollSpy JS (Opsional) */ .custom-toc li.active a { color: #2563eb; font-weight: 700; }
Simulator

Live Preview Generator

Coba ketik struktur heading di kolom kiri untuk melihat bagaimana script kami akan merender daftar isi secara otomatis di kolom kanan.

INPUT (HTML Heading)
OUTPUT (Tampilan ToC)

Troubleshooting FAQ

Secara default kode di atas di-set untuk //h2 | //h3 untuk menjaga daftar isi tetap ringkas. Jika Anda ingin H4, cukup ubah query xpath menjadi //h2 | //h3 | //h4.

Itu sebabnya kami menggunakan fungsi mb_convert_encoding ke HTML-ENTITIES sebelum loading DOM. Ini memastikan karakter UTF-8 diproses dengan aman tanpa menjadi simbol aneh.