ZMedia Purwodadi

Membuat Widget Table of Content & Related Post Otomatis di Blogger - Panduan Lengkap

Table of Contents

Membuat widget Table of Content & Related Post Otomatis di Blogger — Panduan Lengkap

Halo teman-teman sesama blogger! Hari ini saya ingin berbagi pengalaman nyata menyempurnakan blog saya. Membangun blog yang baik bukan hanya soal menulis panjang, tapi juga memastikan pembaca nyaman, mudah menemukan informasi, serta mesin pencari memahami struktur tulisan kita. Itulah sebabnya saya mencari cara untuk membuat Table of Content, membuat Related Post, dan menyusun Daftar Isi Postingan Terkait yang berfungsi sempurna tanpa merusak tampilan template.

Dulu saya sering menyalin kode dari berbagai tempat, tapi hasilnya sering berantakan: tulisan berubah ukuran, warna berantakan, atau tata letak bergeser. Setelah berkali-kali mencoba dan memperbaiki, akhirnya saya menemukan susunan kode yang aman — semua elemen berdiri sendiri, tidak mengganggu gaya asli templat. Berikut panduan lengkapnya.

1. Mengapa Fitur Ini Penting?

Table of Content

Daftar isi membantu pembaca langsung menuju bagian yang dicari tanpa menggulir berulang kali. Dari sisi SEO, struktur yang jelas memudahkan Google memahami isi artikel dan berpotensi tampil lebih baik di hasil pencarian.

Related Post & Daftar Isi Postingan Terkait

Artikel terkait menghubungkan pembaca ke tulisan lain yang topiknya sama. Manfaatnya: menaikkan jumlah halaman dibuka, menurunkan angka pentalan, membantu pembaca menemukan informasi tambahan, serta memperkuat struktur tautan internal yang baik untuk SEO.

2. Hal Penting Sebelum Memasang

  • Sebaiknya cadangkan templat terlebih dahulu sebelum mengedit.
  • Pastikan artikel sudah diberi Label/Kategori agar sistem bisa membaca dan menampilkan artikel terkait.
  • Pasang kode di lokasi yang disarankan saja agar tidak bentrok.

3. Kode Lengkap Siap Salin

Salin semua kode di bawah ini. Jika ingin muncul di seluruh halaman: tempel sebelum </body> di Edit HTML Tema. Jika hanya di artikel ini saja: tempel di bagian bawah saat menyunting artikel dalam mode HTML.

<!-- ==============================================
  Widget TOC & Related Post Otomatis — Aman
  Tidak Mengganggu Tampilan Template
=============================================== -->
<style>
.tombol-tocpost {
  position: fixed;
  top: 50%;
  right: 16px;
  transform: translateY(-50%);
  z-index: 9999;
  background: #2E7D32;
  color: #fff;
  border: none;
  padding: 12px 10px;
  border-radius: 50%;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0,0,0,0.15);
  transition: all 0.25s ease;
}
.tombol-tocpost.aktif-tocpost { background: #c62828; }
.tombol-tocpost:hover { opacity: 0.92; }

.ikon-tocpost {
  width: 18px;
  height: 18px;
  display: block;
  fill: currentColor;
}

.kotak-tocpost {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 9998;
  width: 90%;
  max-width: 320px;
  max-height: 0;
  overflow: hidden;
  border-radius: 12px;
  background: #fff;
  box-shadow: 0 4px 20px rgba(0,0,0,0.18);
  transition: max-height 0.35s ease;
}
.kotak-tocpost.buka-tocpost { max-height: 460px; }

.isi-tocpost {
  padding: 16px;
  overflow-y: auto;
  max-height: 460px;
  box-sizing: border-box;
}
.isi-tocpost h4 {
  margin: 0 0 14px;
  font-size: 15px;
  color: #1a1a1a;
  font-weight: 600;
}

.daftar-tocpost {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.kartu-tocpost {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 10px;
  background: #fafafa;
  border-radius: 8px;
  border: 1px solid #f0f0f0;
  transition: 0.2s ease;
  text-decoration: none;
}
.kartu-tocpost:hover {
  background: #f5f5f5;
  border-color: #e0e0e0;
}

.gambar-tocpost {
  width: 65px;
  height: 65px;
  object-fit: cover;
  border-radius: 6px;
  background: #eee;
  flex-shrink: 0;
}

.judul-tocpost {
  font-size: 14px;
  line-height: 1.4;
  color: #222;
  font-weight: 500;
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.teks-kosong-tocpost {
  font-size: 13px;
  color: #757575;
  padding: 15px 10px;
  text-align: center;
}
</style>

<button class="tombol-tocpost" aria-label="Buka daftar artikel terkait">
  <svg class="ikon-tocpost" viewBox="0 0 24 24">
    <path d="M3 5h18v2H3V5zm0 6h18v2H3v-2zm0 6h18v2H3v-2z"/>
  </svg>
</button>

<div class="kotak-tocpost">
  <div class="isi-tocpost">
    <h4>📄 Artikel Berlabel Sama</h4>
    <div class="daftar-tocpost"></div>
  </div>
</div>

<script>
document.addEventListener("DOMContentLoaded", function () {
  const tombol = document.querySelector(".tombol-tocpost");
  const kotak = document.querySelector(".kotak-tocpost");
  const daftar = document.querySelector(".daftar-tocpost");
  const JUMLAH_MAKSIMAL = 5;
  let sudahDiambil = false;

  function ambilLabel() {
    const tautanLabel = document.querySelectorAll('a[href*="/search/label/"]');
    for (const tautan of tautanLabel) {
      const teks = tautan.textContent.trim();
      if (teks && teks.length > 1 && !teks.includes("Beranda") && !teks.includes("«") && !teks.includes("»")) {
        return teks;
      }
    }
    const cocok = window.location.href.match(/\/search\/label\/([^/?#]+)/);
    if (cocok) return decodeURIComponent(cocok[1].replace(/\+/g, " "));
    return null;
  }

  async function ambilDaftarArtikel(label) {
    const asal = window.location.origin;
    const tautanUmpan = `${asal}/feeds/posts/default/-/${encodeURIComponent(label)}?alt=rss&max-results=${JUMLAH_MAKSIMAL + 5}`;
    try {
      const respon = await fetch(tautanUmpan);
      if (!respon.ok) throw new Error("Gagal mengambil data");
      const xml = new DOMParser().parseFromString(await respon.text(), "text/xml");
      const daftarItem = Array.from(xml.querySelectorAll("item"));
      return daftarItem.map(item => {
        let gambar = "";
        const isi = item.querySelector("description")?.textContent || "";
        const cocokGambar = isi.match(/<img[^>]+src="([^"]+)"/i);
        if (cocokGambar) gambar = cocokGambar[1];
        return {
          judul: item.querySelector("title")?.textContent || "Tanpa Judul",
          tautan: item.querySelector("link")?.textContent || "#",
          gambar: gambar
        };
      });
    } catch {
      return [];
    }
  }

  async function tampilkanDaftar() {
    if (sudahDiambil) return;
    const label = ambilLabel();
    if (!label) {
      daftar.innerHTML = `<div class="teks-kosong-tocpost">⚠️ Artikel ini belum punya Label. Tambahkan dulu di pengaturan artikel.</div>`;
      sudahDiambil = true;
      return;
    }
    const artikel = await ambilDaftarArtikel(label);
    const tautanSekarang = window.location.href;
    const hasil = [];
    for (const a of artikel) {
      if (a.tautan === tautanSekarang) continue;
      hasil.push(`
        <a href="${a.tautan}" class="kartu-tocpost" target="_blank" rel="noopener">
          <img src="${a.gambar || 'https://via.placeholder.com/65x65/f0f0f0/888?text=Gambar'}" 
               alt="${a.judul}" class="gambar-tocpost" loading="lazy">
          <h5 class="judul-tocpost">${a.judul}</h5>
        </a>
      `);
      if (hasil.length >= JUMLAH_MAKSIMAL) break;
    }
    daftar.innerHTML = hasil.length
      ? hasil.join("")
      : `<div class="teks-kosong-tocpost">Belum ada artikel lain berlabel: <strong>${label}</strong></div>`;
    sudahDiambil = true;
  }

  tombol.addEventListener("click", async function () {
    tombol.classList.toggle("aktif-tocpost");
    kotak.classList.toggle("buka-tocpost");
    if (kotak.classList.contains("buka-tocpost")) await tampilkanDaftar();
  });
});
</script>

4. Penutup

Dengan susunan ini, kode fitur tidak akan mengganggu tampilan asli templat karena semua nama kelas menggunakan akhiran khusus -tocpost. Tulis artikel seperti biasa, lalu salin kode di kotak di atas ke lokasi yang diinginkan. Semoga membantu!

⏳ Loading...
JORAN FIBER ULTRA LIGHT SAKURA

iPhone Xr 64/265 GB iBox Fullset

Promo Gratis Ongkir Dan Pembayaran Cod Cek Dulu

Rp 3.900.000 Rp 1.970.000 BELI

📄 Related Post

QRIS Donasi BAYAR LEWAT DANA