May 2, 2021 updated

11ty: Related Books

Shortcode untuk menampilkan related books dengan memanfaatkan JSON data

Di halaman bacaan saya ingin menampilkan relasi buku terkait dengan review buku yang saya tulis.

Tampilan yang diinginkan adalah seperti Twitter Cards dengan gambar dan deskripsi. Gambarnya nanti bisa diisi dengan coverImg dari masing - masing artikel baca yang sudah saya tulis.

Sewu Dino
Simpleman
Dia adalah Dela Atmojo, anak yang harus kamu rawat sampai waktunya tiba. Ia dikirimi kutukan santet sewu dino. Santet yang sudah merenggut nyawa hampir seluruh anggota keluarga Atmojo. ...

Membuat basis data dalam JSON

Hal pertama yang dilakukan adalah membuat basis data dan menyimpannya dalam format JSON. Caranya adalah dengan membuat file baru dan memasukkan data collection dengan format menyesuaikan bentuk format valid dari JSON.

---
permalink : /baca/data.json
---

[{% for post in collections.baca %}
{
"title": "{{ post.data.title }}",
"date": "{{ post.data.date }}",
"url": "{{ post.url }}",
"ringkasan": "{{ post.data.ringkasan }}",
"penulis": "{{ post.data.penulis }}",
"coverImg": "{{ post.data.coverImg }}",
"resensi": "{{ post.data.resensi }}"
}{{ '' if loop.last else ',' }}
{% endfor %}]

title, date, url, ringkasan dan seterusnya adalah field yang sudah saya tulis di YAML/frontmatter pada setiap artikel baca. Tampilan frontmatter seperti ini :

---
layout: isi/buku.njk
title : 'Sewu Dino'
date: 2020-08-17
ringkasan: 'Pertempuran antar keluarga dari Trah Pitu yang memakan banyak korban'
keywords: 'Sewu Dino, Janur Ireng, Ranjat Kembang, Trah Pitu, Simpleman, Horor, Santet'
coverImg : 'https://ik.imagekit.io/hjse9uhdjqd/tr:n-cover/buku/sewuDino_lV8ZEwbP7.jpg'
penulis: 'Simpleman'
genre:
- Thriller
- Mistery
- Jawa
format: 'Papperback - 230 halaman'
bahasa: 'Bahasa Indonesia, Bahasa Jawa'
isbn: '978-602-220-348-3'
tahun: 2020
resensi: 'Dia adalah Dela Atmojo, anak yang harus kamu rawat sampai waktunya tiba. Ia dikirimi kutukan santet sewu dino. Santet yang sudah merenggut nyawa hampir seluruh anggota keluarga Atmojo.'
rating: 3
beli: https://shopee.co.id/bukune
dimana: Bukune
tags: baca
---

Saya mengambil beberapa field yang penting dan hendak dipakai nantinya. Sedangkan hasilnya adalah sebagai berikut

{
"title": "Sewu Dino",
"date": "Mon Aug 17 2020 07:00:00 GMT+0700 (Western Indonesia Time)",
"url": "/baca/sewuDino/",
"ringkasan": "Pertempuran antar keluarga dari Trah Pitu yang memakan banyak korban",
"penulis": "Simpleman",
"coverImg": "https://ik.imagekit.io/hjse9uhdjqd/tr:n-cover/buku/sewuDino_lV8ZEwbP7.jpg",
"resensi": "Dia adalah Dela Atmojo, anak yang harus kamu rawat sampai waktunya tiba. Ia dikirimi kutukan santet sewu dino. Santet yang sudah merenggut nyawa hampir seluruh anggota keluarga Atmojo."
}

Setelah eleventy di build maka akan tersedia 1 file baru dengan nama data.json dengan path /baca/data.json. File inilah yang nanti akan dijadikan basis data untuk menentukan relasi artikel.

11ty Shortcodes

Setelah basis data tersedia, selanjutnya adalah membuat fungsi dalam javascript untuk memanggil basis data tersebut. Disini saya mempergunakan paket node-fetch. Namun sebelum itu perlu menentukan bentuk dari shortcodes yang akan dipakai.

  1. Bentuk shortcodenya. Saya ingin agar bentuk tagsnya adalah sebagai berikut :
{% related "judul" %}

dimana related akan menjadi fungsi pemanggil shortcodes dan judul menjadi string query untuk mencari field di dalam JSON Array.

Sehingga di file eleventy.js saya menambahkan syntax berikut :

eleventyConfig.addLiquidShortcode("related", async function(judul){}

Saya sebenarnya adalah pengguna Nunjucks, namun karena default render markdown di eleventy mempergunakan Liquid. Maka shortcodes saya mempergunakan Liquid

Namun bisa juga mempergunakan global shortcodes dengan kode eleventyConfig.addShortcode yang bisa jalan di semua template tags

  1. Ambil basis data dan buat fungsi query

Seperti yang sudah saya sebutkan diatas, saya mempergunakan node-fetch untuk membantu mengambil basis data. Maka yang harus dilakukan pertama kali adalah memasang paket node-fetch:

$ yarn add node-fetch

# atau

$ npm install node-fetch

Pengguna axios bisa mempergunakannya sebagai pengganti fetch. Silakan menyesuaikan kode dibawah dengan fungsi di axios.

kemudian buat fungsi di dalam shortcodes untuk mengambil basis data :

try {
const response = await fetch('https://kusaeni.com/baca/data.json', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
});
const data = await response.json();
} catch(reason) {
console.log(reason)
}

hasil dari response disimpan sebagai JSON.

  1. Kemudian buat fungsi query untuk mengambil data berdasarkan value judul dengan mempergunakan findIndex
const relasi = function (buku, judul) {
const index = buku.findIndex(function (novel, index) {
return novel.title.toLowerCase() === judul.toLowerCase()
})
return buku[index]
};
const hasilData = await relasi(data, judul);
console.log(hasilData)

Disini string judul harus diamankan dengan membuat judul menjadi huruf kecil semua toLowerCase() untuk menghindari kesalahan tipo saat mengetik judul.

Sampai disini jika tags {% related "judul" %} dimasukkan ke dalam artikel, maka pada saat build/serve, eleventy akan mengambil data.json dan mengfilternya berdasarkan query judul yang dimasukkan. Hasilnya bisa diliat di log di konsol.

  1. Untuk menampilkan data tersebut di posisi tags disisipkan, maka perlu ditambahkan kode berikut :
return `<div class="flex">
<img class="shadow-md" src="
${hasilData.coverImg}" >
<div class="flex-1">
<a href="
${hasilData.url}">${hasilData.title}</a>
<dl>
<dt>
${hasilData.penulis} </d>
<dd>
${rese} ...</dd>
</dl>
</div>
</div>
`
;

Karena node-fetch menghasilkan promise maka return perlu diakses dengan tambahan .then() callback, sehingga keseluruhan shortcodesnya menjadi seperti ini :

eleventyConfig.addLiquidShortcode("related", async function(judul){
try {
const response = await fetch('https://kusaeni.com/baca/data.json',{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
});
const data = await response.json();
const relasi = function (buku, judul) {
const index = buku.findIndex(function (novel, index) {
return novel.title.toLowerCase() === judul.toLowerCase()
})
return buku[index]
};
const hasilData = await relasi(data, judul);
var rese = hasilData.resensi.substr(0, 200)
return `<div class="flex">
<img class="shadow-md" src="
${hasilData.coverImg}" >
<div class="flex-1">
<a href="
${hasilData.url}">${hasilData.title}</a>
<dl>
<dt>
${hasilData.penulis} </d>
<dd>
${rese} ...</dd>
</dl>
</div>
</div>
`
;
} catch (err) {
console.log(err)
}
const print = async () => {
const p = await hasilData;
console.log(p)
};
print()
});

Saya menambahkan fungsi rese untuk memotong karakter di resensi agar tidak lebih dari 200 karakter.

Update

Saya menambahkan fungsi yang sama untuk menampilkan relasi artikel di collection jurnal dengan sedikit perbedaan yaitu tanpa coverImg dan tanpa mempergunakan fetch JSON. Meskipun kode diatas bisa juga diaplikasikan di collection apa saja, namun saya tidak memakainya dengan alasan performa.

Di jurnal saya hanya ingin menampilkan relasi artikel dengan format judul, url, dan desk atau deskripsi.

Saya memakai fungsi lain shortcodes yaitu paired shortcodes. Seperti diatas, tulis kode beriku di file .eleventy.js

eleventyConfig.addPairedShortcode("prelated", 
function(desk, judul, url){
return `<div class="relasi-artikel">
<h4 class="header-relasi">Artikel terkait</h4>
<a class="link" href="$url" title="
${judul}">${judul}</a>
<p class="desk-relasi">
${desk}</p>
</div>
`
;
});

Sesuai namanya paired maka shortcodes ini akan membuat template tags baru dengan tags buka dan tutup.

{% prelated "11ty Reader Bar", "/jurnal/11tyReaderBar" %}
11ty Reader Bar : sebuah plugin shortcodes untuk menampilkan readerbar di eleventy
{% endprelated %}

Dengan catatan :

  • 11ty Reader Bar” akan diproses sebagai variable judul,
  • /jurnal/11tyReaderBar” sebagai url,
  • 11ty Reader Bar : sebuah plugin shortcodes untuk menampilkan readerbar di eleventy” sebagai desk

Artikel terkait

11ty Reader Bar

Sebuah plugin shortcodes untuk menampilkan readerbar di eleventy

Shortcode ini bisa juga dipergunakan untuk menggantikan shortcodes dengan parse JSON. Hanya saja setiap hendak menyisipkan related books harus mengetikkan secara manual setiap data yang ingin ditampilkan.

Kesimpulan dan catatan

Alhamdulillah dengan fungsi shortcodes ini saya bisa menampilkan relasi bacaan sesuai dengan keinginan, namun ada beberapa hal yang perlu diperhatikan saat mempergunakan shortcodes ini, diantaranya :

  1. Untuk mengurangi kesalahan dalam query data berdasarkan judul, maka judul perlu dibuat lowerCase semua. Namun hal ini tidak menjadi solusi jika penulisan judulnya salah karena salah ketik atau salah spasi,
  2. Proses ini harus mengambil data.json dan melakukan parse serta query membuat waktu build menjadi lebih lama, sekitar 19 - 30 ms dimana sebelumnya sekitar 9 - 17 ms.

Saya melakukan DEBUG build eleventy dan hasilnya butuh waktu 8,9 ms sendiri untuk membaca dan menyelesaikan eksekusi file eleventy.js.

Namun masih di dalam hitungan miliseconds dan saya tidak keberatan dengan ini dan pastinya jatah build dari Netlify masih jauh dari waktu terlampaui.

Berlangganan artikel

Suka dengan artikel seperti ini?, yuk berlangganan melalui RSS atau ketik emailmu di bawah ini untuk mendapatkan update artikel terbaru langsung ke inboxmu.

Kamu bisa berhenti berlangganan dengan mudah kapan saja.

Powered by Buttondown.