Membuat Fitur Komentar Berbalas (Threaded Comments) pada Blogger dengan Fungsional yang Asli
Pembaruan 2018/05/17: Sintaks dan struktur HTML sudah berubah. Beberapa diskusi yang terdapat di dalam ruang komentar mungkin sudah tidak relevan lagi dengan isi artikel.
Setelah berhasil menemukan beberapa metode untuk menciptakan komentar bersarang (atau berbalas??) pada Blogger, Saya rasa metode dari bX-NicoNico adalah yang paling bagus. Mengapa?
- Dia tidak menggunakan elemen
<data:post.commentJso/>
sebagai salah satu elemen yang dibutuhkan untuk sistem ini, sehingga markup HTML akan menjadi lebih pendek dari markup HTML pada template dengan fitur komentar bersarang yang masih standar. (Fitur komentar bersarang yang masih standar akan menampilkan JSON komentar sebelum daftar komentar, sehingga jumlah karakter markup HTML pada fitur komentar bersarang yang masih standar akan menjadi dua kali lipat lebih panjang dibandingkan markup komentar biasa. - Layout komentar tertata secara otomatis. JavaScript hanya digunakan untuk mengubah URL pada
iframe
formulir komentar dan juga untuk memindahkan posisinya sesuai dengan ID komentar induk masing-masing. - Karena layout komentar ditata secara otomatis oleh Blogger, maka saat JavaScript dimatikan, tata letak komentar balasan akan tetap berada pada posisi yang benar. Ini berbeda dengan beberapa hack komentar bersarang Blogger yang hanya menggunakan JavaScript (yang juga telah Saya pakai sampai sekarang) untuk memposisikan komentar-komentar balasan, sehingga saat JavaScript dimatikan, layout komentar akan berantakan.
Berikut ini adalah fitur komentar versi Saya yang lebih pendek dan lebih mudah dalam hal instalasi yang Saya buat berdasarkan konsep dari Felipe, yaitu dengan cara menggunakan elemen data
baru bernama <data:comment.inReplyTo/>
untuk menyaring anak-anak komentar yang tampil. Elemen ini berfungsi untuk menampilkan ID komentar induk pada masing-masing komentar balasan. Saya bisa mengatakan bahwa metode ini adalah metode yang paling tepat dan bukan merupakan “hack”, karena kita menerapkan elemen yang ada dari Blogger untuk dimanfaatkan sesuai dengan tugasnya:
Mengaktifkan Fitur Komentar Bersarang pada Blogger
Pertama-tama buka editor HTML template Anda kemudian cek Expand Template Widget. Temukan kode ini:
]]></b:skin>
Salin kode CSS ini dan letakkan di atasnya:
/* Begin custom comments */
.comments,
.comment {
margin: 0;
padding: 0;
list-style: none;
letter-spacing: 0;
}
.comments::after,
.comment::after,
.comment-header::after,
.comment-body::after,
.comment-footer::after {
content: "";
display: table;
clear: both;
}
.custom-comments {
margin: 3em 0 0;
font: normal normal 13px/1.4 Tahoma, Helmet, FreeSans, sans-serif;
}
.custom-comments a {
color: #2143b4;
text-decoration: none;
}
.custom-comments a:hover {
text-decoration: underline;
}
.custom-comments .comment {
margin: 0 0 .5em;
padding: 0 0 .75em 0;
border-bottom: 1px solid #eee;
position: relative;
}
.custom-comments .comment-header {
margin: 0 0 1em 0;
}
.custom-comments .comment-author {
float: left;
}
.custom-comments .comment-url {
float: right;
}
.custom-comments .comment-avatar {
width: 65px;
margin: 0;
padding: 0;
background: 0 0;
border: 0;
float: left;
}
.custom-comments .comment-avatar a,
.custom-comments .comment-avatar img {
margin: 0;
padding: 0;
background: 0 0;
border: 0;
display: block;
float: none;
width: 50px;
height: 50px;
min-width: 0;
min-height: 0;
max-width: 100%;
max-height: 100%;
}
.custom-comments .comment-avatar img {
border: 1px solid #ddd;
padding: 4px;
background: #fafafa;
}
.custom-comments .comment-body {
margin: -5px 0 1em 75px;
}
.custom-comments .comment.reply {
margin: 0 0 1em 75px;
padding: 1em 1.2em;
background: #fff7d1;
border: 0;
position: relative;
font-size: 86%;
}
.custom-comments .comment.reply::after {
content: "";
display: block;
width: 0;
height: 0;
position: absolute;
top: 0;
left: 0;
border: 10px solid transparent;
border-color: #fff #f5f2d8 #f5f2d8 #fff;
}
.custom-comments .comment.reply .comment-author {
margin-left: 15px;
}
.custom-comments .comment.reply a {
color: #767643;
}
.custom-comments .comment.reply .comment-avatar img {
border-color: #eae5c4;
background: #f5f0d3;
}
.custom-comments .comment-footer {
margin: 0 0 .125em 75px;
text-align: right;
}
.custom-comments .comment-footer a,
.custom-comments .a-undo {
display: inline-block;
border: 1px solid #ddd;
padding: .15em .65em .2em;
margin: 0 0 0 .25em;
border-radius: 1em;
text-decoration: none;
outline: none;
}
.custom-comments .comment.reply .comment-footer a {
border-color: #eae5c4;
}
.custom-comments .comment-footer .a-reply::before {
content: '\2714';
color: #3db537;
display: inherit;
margin: 0 .25em 0 -.125em;
}
.custom-comments .comment-footer .a-delete::before {
content: '\2718';
color: #b42a21;
display: inherit;
margin: 0 .25em 0 -.125em;
}
.custom-comments .comment-footer a:hover,
.custom-comments .a-undo:hover {
border-color: #ccc;
text-decoration: none;
}
.custom-comments .comment-footer a:focus,
.custom-comments .comment-footer a:active,
.custom-comments .a-undo:focus,
.custom-comments .a-undo:active {
border-color: #aaa;
}
.custom-comments .comment.reply .comment-footer a {
background: #fffad6;
border-color: #e3deb7;
}
.custom-comments .comment.reply .comment-footer a:hover {
border-color: #d6d1aa;
}
.custom-comments .comment.reply .comment-footer a:focus,
.custom-comments .comment.reply .comment-footer a:active {
border-color: #bcb795;
}
.custom-comments .custom-comment-form {
margin: 1em 0 2em;
clear: both;
}
.custom-comments .comment .custom-comment-form {
border: 1px solid #eee;
padding: 1em;
margin-left: 75px;
}
.custom-comments #comment-editor {
max-width: none;
width: 100%;
height: 250px;
background: 0 0;
border: 0;
}
.custom-comments .custom-comment-form .a-undo {
display: none;
}
.custom-comments .comment .custom-comment-form .a-undo {
display: inline-block;
}
.custom-comments .comment .custom-comment-form h4 {
display: none;
}
.custom-comments .custom-comment-editor-wrapper {
background: transparent url('data:image/gif;base64,R0lGODlhEgAEAKEAAH9/fwAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJDwACACwAAAAAEgAEAAACB5SPqcvtrwoAIfkECQ8AAgAsAAAAAAQABAAAAgSEjwkFACH5BAkPAAIALAAAAAALAAQAAAIMjCMJC4fKXBKsnVkLACH5BAkPAAIALAAAAAASAAQAAAIRjCN5mOCwkojt0Xnkg1l1sRUAIfkECQ8AAgAsAAAAABIABAAAAhGEIRkbKRwOUsxBaStdeDdfAAAh+QQJDwACACwHAAAACwAEAAACDIQhGRuHylwSrJ1ZCwAh+QQFDwACACwOAAAABAAEAAACBISPCQUAOw==') no-repeat 50% 50%;
}
.custom-comments-pager {
font-size: 80%;
text-align: center;
width: auto;
height: auto;
line-height: normal;
margin: 1em 0;
float: none;
display: block;
clear: both;
border: 1px solid #eee;
padding: .5em 1em;
overflow: hidden;
}
.custom-comments-pager .unneeded-paging-control {
display: none;
}
.custom-comments-pager .paging-control {
display: inline;
}
/* Author comment style */
.custom-comments .comment.is-author {}
.custom-comments .comment.is-author > .comment-header {}
/* Deleted comment style */
.custom-comments .comment.is-deleted > .comment-body {
font-style: italic;
color: #aaa;
}
/* End custom comments */
Kemudian cari kode ini:
<b:includable id='comments' var='post'>
Salin kode ini, dan letakkan di atasnya:
<b:includable id='custom-comments' var='post'>
<b:with value='{
cancel: "Cancel",
comment: "Comment",
comments: "Comments",
delete: "Delete",
reply: "Reply"
}' var='text'>
<section class='custom-comments' id='custom-comments'>
<b:if cond='data:post.allowComments'>
<h4>
<b:if cond='data:post.numberOfComments == 1'>
<span>1</span> <data:text.comment/>
<b:else/>
<span><data:post.numberOfComments/></span> <data:text.comments/>
</b:if>
</h4>
<b:if cond='data:post.numberOfComments > 0'>
<ul class='comments'>
<b:loop values='data:post.comments' var='comment'>
<b:if cond='!data:comment.inReplyTo'>
<b:include data='comment' name='custom-comments-comment'/>
</b:if>
</b:loop>
</ul>
</b:if>
<b:include data='post' name='custom-comments-pager'/>
<b:include data='post' name='custom-comments-form'/>
</b:if>
</section>
</b:with>
</b:includable>
<b:includable id='custom-comments-comment' var='comment'>
<li class='comment' expr:id='data:comment.anchorName'>
<b:class cond='data:comment.authorClass' name='is-author'/>
<b:class cond='data:comment.isDeleted' name='is-deleted'/>
<header class='comment-header'>
<strong class='comment-author'>
<b:if cond='data:comment.authorUrl'>
<a expr:href='data:comment.authorUrl' rel='nofollow' target='_blank'><data:comment.author/></a>
<b:else/>
<data:comment.author/>
</b:if> <data:commentPostedByMsg/>
</strong>
<a class='comment-url' expr:href='data:comment.url'><data:comment.timestamp/></a>
</header>
<figure class='comment-avatar'>
<img alt='' expr:src='resizeImage(data:comment.authorAvatarSrc, 50)'/>
</figure>
<div class='comment-body'>
<data:comment.body/>
</div>
<b:with value='data:post.comments filter (i => i.inReplyTo == data:comment.id)' var='replies'>
<b:if cond='data:replies.size > 0'>
<ul class='comments replies'>
<b:loop values='data:replies' var='reply'>
<b:include data='reply' name='custom-comments-comment-reply'/>
</b:loop>
</ul>
</b:if>
</b:with>
<footer class='comment-footer'>
<b:if cond='!data:comment.isDeleted'>
<a class='a-reply' expr:href='"javascript:replyTo(&quot;" + data:comment.id + "&quot;);"'><data:text.reply/></a>
</b:if>
<a class='a-delete' expr:href='data:comment.deleteUrl' expr:title='data:top.deleteCommentMsg'><data:text.delete/></a>
</footer>
</li>
</b:includable>
<b:includable id='custom-comments-comment-reply' var='reply'>
<li class='comment reply' expr:id='data:reply.anchorName'>
<b:class cond='data:reply.authorClass' name='is-author'/>
<b:class cond='data:reply.isDeleted' name='is-deleted'/>
<header class='comment-header'>
<strong class='comment-author'>
<b:if cond='data:reply.authorUrl'>
<a expr:href='data:reply.authorUrl' rel='nofollow' target='_blank'><data:reply.author/></a>
<b:else/>
<data:reply.author/>
</b:if> <data:commentPostedByMsg/>
</strong>
<a class='comment-url' expr:href='data:reply.url'><data:reply.timestamp/></a>
</header>
<figure class='comment-avatar'>
<img alt='' expr:src='resizeImage(data:reply.authorAvatarSrc, 50)'/>
</figure>
<div class='comment-body'>
<data:reply.body/>
</div>
<footer class='comment-footer'>
<a class='a-delete' expr:href='data:reply.deleteUrl' expr:title='data:top.deleteCommentMsg'><data:text.delete/></a>
</footer>
</li>
</b:includable>
<b:includable id='custom-comments-form' var='post'>
<div class='custom-comment-form' id='custom-comment-form'>
<h4><data:postCommentMsg/></h4>
<p><data:blogCommentMessage/></p>
<data:blogTeamBlogMessage/>
<a expr:href='data:post.commentFormIframeSrc' id='comment-editor-src'/>
<div class='custom-comment-editor-wrapper'>
<iframe class='blogger-iframe-colorize blogger-comment-from-post' id='comment-editor' name='comment-editor' src=''/>
</div>
<data:post.friendConnectJs/>
<data:post.cmtfpIframe/>
<script>BLOG_CMT_createIframe('<data:post.appRpcRelayPath/>', '<data:post.communityId/>');</script>
<a class='a-undo' href='javascript:replyTo(0);'><data:text.cancel/></a>
</div>
<script>
//<![CDATA[
var originalSource = document.getElementById('comment-editor').src.split('#');
function replyTo(id) {
var frame = document.getElementById('comment-editor'),
form = document.getElementById('custom-comment-form'),
container = id ? document.getElementById('c' + id) : document.getElementById('custom-comments'),
part = originalSource;
frame.style.height = '50px';
frame.style.visibility = 'hidden';
frame.src = id ? part[0] + '&parentID=' + id + '#' + part[1] : part[0] + '#' + part[1];
container.insertBefore(form, null);
frame.onload = function() {
this.style.height = '250px';
this.style.visibility = 'visible';
};
}
//]]>
</script>
</b:includable>
<b:includable id='custom-comments-pager' var='post'>
<b:if cond='data:post.commentPagingRequired'>
<nav class='custom-comments-pager'>
<a expr:class='data:post.oldLinkClass' expr:href='data:post.olderLinkUrl'><data:post.olderLinkText/></a> 
<a expr:class='data:post.oldLinkClass' expr:href='data:post.oldestLinkUrl'><data:post.oldestLinkText/></a> 
<data:post.commentRangeText/> 
<a expr:class='data:post.newLinkClass' expr:href='data:post.newestLinkUrl'><data:post.newestLinkText/></a> 
<a expr:class='data:post.newLinkClass' expr:href='data:post.newerLinkUrl'><data:post.newerLinkText/></a>
</nav>
</b:if>
</b:includable>
Terakhir tinggal mengaktifkan fitur komentar kita. Cari semua kode yang tampak seperti ini:
<b:include data='post' name='threaded_comments'/>
atau seperti ini:
<b:include data='post' name='comments'/>
Di manapun Anda menemukan kode itu, segera ganti dengan kode ini:
<b:include data='post' name='custom-comments'/>
Klik Simpan Template.
Konfigurasi
Kode-kode yang Saya beri tanda adalah label-label tombol dan bisa Anda ganti teksnya sesuka hati sesuai dengan bahasa pada negara dimana Anda tinggal. Fitur penanda komentar administrator juga ada. Untuk mengaktifkannya, Anda bisa menggunakan selektor-selektor CSS yang tercantum di atas, kemudian awali dengan kelas .is-author
untuk menandai komentar penulis. Sebagai contoh, Saya akan memberikan border warna merah dan latar warna kuning pada komentar administrator, maka yang harus Anda lakukan adalah seperti ini:
.comment.is-author {
border: 5px solid #900;
background-color: #ff0;
}
.comment.is-author > .comment-body {
font-size: 200%;
}
Catatan: Bagi Anda yang selama ini telah lama menggunakan fitur komentar bersarang lebih dari dua level (seperti blog Saya), sangat disarankan untuk tidak menerapkan modifikasi di atas, karena Saya hanya menggunakan loop komentar balasan sebanyak satu kali:
<b:loop values='data:post.comments' var='reply'>
<b:if cond='data:reply.inReplyTo == data:comment.id'>
Komentar balasan muncul di sini…
</b:if>
</b:loop>
Seperti yang Anda lihat bahwa Saya hanya membandingkan nilai data:var.inReplyTo
pada komentar balasan dengan ID komentar induk sekali saja (satu kali loop), sehingga jika komentar balasan lama Anda berada di level ke tiga dan seterusnya, komentar-komentar tersebut tidak akan tampil dalam posting Anda dikarenakan ID komentar induknya tidak sempat lolos penyaringan terhadap data:var.inReplyTo
pada anak komentar di level tersebut.
Blog yang masih baru atau blog lama dengan sedikit komentar dan blog dengan fitur komentar yang masih lama bisa melakukan modifikasi ini dengan aman.
145 Komentar
Unknown
Mas Taufik sya mau tanya, sya kan pake code ini, tapi knpa ya ketika dibuka di hape kokgak ada formulir komentarnya, pdhal sudah tak kasih
ini kode sya mas
Taufik Nurrohman
Kalau di HP biasanya URL blog langsung diarahkan ke
?m=1
. Tampilan komentar ini cuma kelihatan di dalam blog versi web. Untuk mengatasinya bisa dengan cara menonaktifkan tampilan mobile.Selengkapnya → /2013/01/bekerja-dengan-blog-seluler.html
tonohidayat
Mas mau tanya kenapa tombol replay di komentar blog saya gak berfungsi y? Tolong dicek mas, masstono.blogspot.com
Taufik Nurrohman
Kamu pakai sistem komentar orang lain yang sudah dikompresi, Saya jadi tidak mengerti.
Unknown
ada yang baru ik,
tombol tampilkan komentar, keren keren :D
ajarin donk, wkwkwk
Taufik Nurrohman
Nanti Saya kasih kode JSON mentahannya untuk dikreasikan sendiri, sekalian juga untuk JSON posting, supaya pada bisa bikin widget sendiri-sendiri…
Unknown
\o/
Admin
Om, kalo dikomentarnya bisa mention yang koment (kaya di Facebook) bisa ga?
Unknown
kalo pake thread comment ini terus javascript reply nya dibikin pake
document.querySelectorAll
kayak pertanyaanku yang ini bisa nggak mas ?/2012/03/jquery-auto-emoticons-for-blogger.html?showComment=1433318084347#c665188069510842762
bingung udah utak atik sendiri gagal terus
Unknown
udah berhasil mas :)
ini, wkwkw Hasil Eksperimen
Unknown
whew keren mas \o/ :-bd
Unknown
mas
cond='data:comment.favicon'
itu apa?apa ini yang menghasilkan
class="delayLoad"
di avatar?Game Cover
hi, this working with google plus comment system?
Nurlailah Yahya
Saya kok gagal yah... tidak ada yang berubah sama sekali. Orang yang komentar di blogku, tdk bisa direply
Taufik Nurrohman
Biasanya ada dua tipe templat komentar di tema Blogger, yaitu untuk tampilan desktop dan untuk tampilan seluler. Mungkin kamu tidak sengaja mengedit templat komentar versi seluler.
Irfan Muhammad Ghani
gan mohon bantuannya kalau page komentar / tombol next komentar, untuk komentar yang sudah banyak sekali tidak muncul kenapa ya gan? :'( terimakasih.. :)
Irfan Muhammad Ghani
load more komentar yang lebih dari 200 komentar tidak mau muncul..
Failed to execute 'write' on 'Document': It isn't possible to write into a document from an asynchronously-loaded external script unless it is explicitly opened.
Xb @ comments.js:3
saya liat di console chrome kayak gitu gan pesan errornya.. solusinya gimana ya gan? terimakasih banyak :)
Taufik Nurrohman
Coba hapus atribut
async
dari skrip yang kurang lebih tampak seperti ini:Unknown
bermanfaat banget... terima kasih
tapi gan mau tanya dikit, gimana caranya komentar dan komentar balasan biar bisa di hidden?
Taufik Nurrohman
Masalahmu mirip sama konsepnya mas Satank, agak sulit untuk direalisasikan.
Anonim
I have been browsing on-line greater than three hours these days, yet I by
no means discovered any attention-grabbing article like yours.
It is beautiful worth enough for me. Personally,
if all web owners and bloggers made just right content as you probably did, the net
will probably be much more helpful than ever before.
Saeful Rahman
Saya melakukan modifikasi pada desain komentarnya dan saya taruh tombol "Reply" berada diatas sebelah nama user. Bagaimana caranya saat tombol "Reply" di klik otomatis scroll ke
#comment-editor
Saeful Rahman
Saya sudah berhasil menambahkan efek scroll pada form komentar ketika button reply di klik. Lalu bagaimana caranya menambahkan fungsi smooth scrolling pada fungsi ini. Saya menggunakan fungsi
document.getElementById("form-container-" + h).scrollIntoView();
untuk scroll ke form editor. Sejauh ini saya mencoba masih gagal dan kurang paham, mohon bantuannya<script type='text/javascript'>
/*<![CDATA[*/
var originalSource = document.getElementById("comment-editor").src.split("#");
function replyTo(h) {
var i = document.getElementById("comment-editor"),
j = document.getElementById("custom-comment-form"),
g = (h != "cancel") ? document.getElementById("form-container-" + h) : document.getElementById("comments"),
f = originalSource;
i.style.height = "50px";
i.style.visibility = "hidden";
i.src = (h != "cancel") ? f[0] + "&parentID=" + h + "#" + f[1] : f[0] + "#" + f[1];
g.insertBefore(j, null);
i.onload = function() {
this.style.height = "250px";
this.style.visibility = "visible";
document.getElementById("form-container-" + h).scrollIntoView();
}
};
/*]]>*/
</script>
Taufik Nurrohman
Kamu perlu mengubah selektor JavaScript menjadi selektor jQuery:
Saeful Rahman
Mkasih mas, saya coba blum berhasil atau saya salah dalam implementasinya? Saya berhasil dg cara ini.
document.getElementById("form-container-" + h).scrollIntoView({ block: 'start', behavior: 'smooth' });
Maulida Dzul Fikri
Mas Taufik,
Komentar ini 4807286072313748141 bisa kita submit di jendela halaman baru. Berikut adalah tautannya:
Sebenarnya tautan formulir komentar balasan Blogger di atas, bisa kita dapatkan tanpa Javascript. Apakah ada cara untuk membuat tautan di atas sebagai tag iframe tanpa Javascript setiap pengunjung akan membalas komentar tertentu?
Ataukah itu terdengar lucu dengan mendeklarasikannya sebagai iframe dalam setiap komentar dan/atau komentar balasan dalam elemen HTML, sehingga pada akhirnya pemuatan halaman menjadi berat karena sejumlah tag iframe dimuat sebanyak komentar yang ada, semisal 200 komentar maka akan ada 200 iframe dengan atribut src berupa tautan komentar Blogger seperti yang saya jelaskan di atas.
Namun, ini akan menarik jika dapat dilakukan. HTML memiliki tag details dan summary.
Gambarannya seperti ini:
Kita bisa membuat beberapa elemen seperti di atas dalam setiap loop komentar. Adakah solusi untuk tidak ikut menyertakan dalam pemuatan halaman ketika postingan kita dibuka. elemen details yang berisi iframe formulir komentar hanya akan dimuat ketika tag summary mendapatkan klik saja.
Salam, sekian terimakasih.
Taufik Nurrohman
Cukup pakai satu iframe saja. Nanti ditambahkan atribut
name
sebagai target. Buat efek loncatan pakai fragmen URL.→ /2012/01/open-link-to-iframe.html
lutfiyah
Mas, ketika saya ganti kode ini:
<b:include data='post' name='threaded_comments'/>
dengan<b:include data='post' name='custom-comments'/>
, komentar aman-aman saja.Pada saat saya ganti juga kode ini:
<b:include data='post' name='comments'/>
dengan<b:include data='post' name='custom-comments'/>
, formulir komentar beserta komentar yang ada tidak muncul.Apa memang kita harus mengganti hanya kode pertama saja? Atau bagaimana?
Samsul Arif
Mantap. Postingan 2013 berguna sekali bagi saya yg baru paham sekarang, hahaha :D