過去記事を参照したときには、リンクを張っている。このリンクは、新記事から旧記事へのリンクでしかない。旧記事からは、リンクされたことは判らない。そしてそんな旧記事が、検索に掛かることがままある。
旧記事にも、関連のある最新記事へのリンクが欲しい。それも自動的につけてほしい。
調べてみるとbloggerには、バックリンクという機能があるらしい。ビンゴ! かと思いきや、どうやら「リンクしましたよ」と、その記事に対して伝えないといけないらしい。手動かよ……
少し間口を広げて、直接的な「被リンク検出」ではなくても、関連記事を並べてくれるようなサービスがないか、ネット上を調べてみた。
関連記事をリストアップする、というスクリプトは、いくつか発表されている。
クリボウ氏のページでは、blogger用のものが2種類、紹介されている。Related Postなどと呼ばれ、いずれも記事に付加された「ラベル」から検出しているらしい。
比較的最近の記事では、Smarter Related Posts ~v2.0というものもある。すなふ氏のページなどに紹介があるが、これもラベルを元にリストアップしているよう。
このv2.0を導入してみた。ページ下部の「関連記事 by Related Posts v2.0」がそれに該当する。
導入は、easy setup wizardサイトでコードを得、bloggerの「HTML/JavaScript」ガジェットにコピペする。
setupサイトでは、ブログのトップページURLを入力したほか、Max Postsを「10」に、Show Thumbs?を「no」に、Related Titleを「関連記事~」に変更した。
以下が貼り付けたソース。得られたコードには、少しお足しをしている。
ピンクが追加した部分で、他とのバランスを考え、表示される文字のスタイルを変更した。
なお、Webページ上の特定部分が、ソースのどこに該当するのかを調べるのに、Google Chromeを使用した。調べたいところで右クリックし、メニューから「要素を検証(N)」とすると、該当するソースが見られる。これは便利。
<!--~~~~~~~~~~~~~~~~~ Include these JS files once: jQuery then plugin -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="http://blogger-related-posts.googlecode.com/files/jquery.related-posts-widget-2.0.min.js"></script>
<!---~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
<!--~~~~~~~~~~~~~~~~~~~~~~~ required HTML -->
<style>
div.related-posts-widget h2{
font-weight:normal !important;
font-size:medium !important;
}
div.related-posts-widget ul.rpw li a strong{
font-weight:normal; !important;
}
</style>
<div class="related-posts-widget">
<!-- {
blog_url:'http://k-ichi.blogspot.jp/'
,max_posts:10
,related_title:'関連記事 by Related Posts v2.0'
,thumbs:0
} -->
loading..
</div>
<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
blogger以外でも使える一般向けサービスとしては、LinkWithinやZenbackが有名どころのよう。Outbrainを挙げているページもある。
ラベル等blogger特有要素は使えないので、文章内容などから推測していると思われる。LinkWithinは「ブログ内」の、Zenbackは「ブログ内」と「それ以外のZenbackユーザ」の両方の、関連記事が表示される。表示内容の細かな設定はできないらしい。
ともかく繋がりが欲しい向きには、Zenbackのブログ外リンクは重宝しそう。また日本の会社なので、サポート等を考えると、モノリンガルには心強いかもしれない。
ここでは、LinkWithinを使ってみた。下部の「関連記事 by LinkWithin」がそれ。
LinkWithinのサイトで、必要事項を入力すればコードが得られる。
Platformに「Blogger」の選択肢があるが、ここでは「Other」としておいた。Widthは検出記事数なので、最大の「5 stories」とした。
あとから設定を変えたい場合は、再度このページで設定しなおす。コードが得られるが、実は一字一句変わっていない。どうやら、登録したURLからRSSフィードURLを推測し、それに対してユニークなIDを振っているよう。各種設定は、このIDに関連付けられて、サーバ側に記録される。したがって、何度再設定しても問題ない。また、TLDが.jpでも.comでも、同じブログとして認識してくれる。
コードは以下のとおり。追加部分は3ヶ所。
標準のままでは、トップページ表示時に、記事毎にリストが表示されてしまう。ガジェット部分だけに表示されるように、classを定義した(紫)。また、スタイルで文字の太さと位置調整をし(水色)、表示タイトルも変更した(ピンク)。位置調整は、文字のみのリストが表示されたときに意味を持つ。ブラウザによってデフォルト値が異なるので、設定前に読み取って出力内容に書き込みたかったが、かなり手間(例1、例2、例3)なため、「1.5文字」という固定値とした。
<div class="linkwithin_div"></div> <style> div.linkwithin_text{ font-weight:normal !important; } ul.linkwithin_textlist li{ margin:0 0 0 1.5em !important; } </style> <script> var linkwithin_site_id = 1392455; var linkwithin_text='関連記事 by LinkWithin'; </script> <script src="http://www.linkwithin.com/widget.js"></script> <a href="http://www.linkwithin.com/"><img src="http://www.linkwithin.com/pixel.png" alt="Related Posts Plugin for WordPress, Blogger..." style="border: 0" /></a>
上記いずれも、なかなか使える。なぜこの記事が? というものも含まれるが、むしろ新しい発見があっていいかもしれない。ただ、本来の目的である、被リンク記事を漏らしていることがあった。片方でしか検出されないことが結構ある。仕方ないので、手作りすることにした。
当初は、サーバ側に検索など処理を任せて結果のHTMLだけを得るとか、Googleなどからリンク関連の情報をもらうとか、虫のいい妄想をしていた。結局はいずれも無理と判断し、クライアント側でスクリプトで処理することとした。
作成に当たっては、いくつか制限をつけた。
bloggerユーザは、ごく日常的に(?)テンプレートのXMLをいじる。それによって、blogger特有のデータが得られたり、好きなところへパーツを置けたりする。が、正直なところ管理が面倒になってきた。よって、HTML/JavaScriptガジェットの中に置いて完了できるもの、とした。
また、後に内容を忘れても運用ができるように、スクリプト自体に特段の設定は要らないようにした。スクリプトは、自身が置かれた場所から、標準的な機能だけを使って各種URLを想定、処理する。bloggerを始めたままのノーマルな状態なら、スクリプトをそのまま貼ってすぐ使用可能。
さらには、表示メッセージなどは好みで変え易いように、冒頭で変数に入れるようにした。
動作内容とコードは、以下のとおり。
このスクリプトは、このブログでは常に表示されている。まずは現在のURLから、検出に適したページかどうかチェックする。適合ページであれば、公開済みの記事をすべて読み込み、このページのURLが含まれるものを探す。すべてリストアップし、その結果を「id_20120829_localBacklinks」のID部分に出力する。
記事の読み込みには、JSON形式のフィードデータを使う。URLには、.comや.jpのようにTLDの異なるものがあるが、同一とみなして処理する。フィードデータ受信に必要なXMLHttpRequestは、IE7以降の機能ということなので、Wikipediaを参考に下位互換を考慮する。またJSONデータのパースを行うJSON.parseは、IE8以降の機能ということなので、状況によってはevalを使うようにする。
このスクリプトは、Win7 IE9、Win7 XPM IE6、およびWin7 Chrome22で動作を確認している。
この記事へのリンク <div><ul><span id='id_20120829_localBacklinks'></span></ul></div> <script type='text/javascript'><!-- var loadingText = '検索中……'; var noResultText = '( 被リンクなし )'; var notSearchText = '( 複合/特殊ページ )'; var maxTarget = 9999; var path = location.pathname; var myUrl = 'http://' + location.host + path; var feedUrl = 'http://' + location.host + '/feeds/posts/full?alt=json&orderby=published'; var regexMyUrl = myUrl.replace(/\.blogspot\..+?\//i,'.blogspot.[a-z]+/').replace(/\//g,'\\/').replace(/\./g,'\\.'); var LBList = ''; var doc = document.getElementById("id_20120829_localBacklinks"); var addLi = function(str){return '<li>'+str+'</li>';}; var xhr = new function(){ if(window.XMLHttpRequest) {return new XMLHttpRequest();} if(window.ActiveXObject) { try{return new ActiveXObject("Msxml2.XMLHTTP.6.0");}catch(e){} try{return new ActiveXObject("Msxml2.XMLHTTP.3.0");}catch(e){} return new ActiveXObject("Microsoft.XMLHTTP"); } }; function getJson(sta,len){ xhr.open('GET',feedUrl+'&start-index='+sta+'&max-results='+len,true); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { try{var obj = JSON.parse(xhr.responseText);}catch(e){var obj = eval("("+xhr.responseText+")");} for(var i=0; i<obj.feed.entry.length; i++){ var ent = obj.feed.entry[i]; if(RegExp(regexMyUrl,'i').test(ent.content.$t)){ for(var j=0; j<ent.link.length; j++){ if(ent.link[j].rel == 'alternate'){ LBList += addLi('<a href="' + ent.link[j].href + '">' + (ent.published.$t).match(/.{10}/) + ' : ' + ent.link[j].title + '</a>'); } } } } var nextTarget = obj.feed.openSearch$startIndex.$t-0 + obj.feed.entry.length-0; doc.innerHTML = addLi(loadingText + ~~((nextTarget-1)/obj.feed.openSearch$totalResults.$t*100) + '%'); if(nextTarget <= Math.min(maxTarget,obj.feed.openSearch$totalResults.$t)){ getJson(nextTarget,101); }else{ if(LBList == ''){doc.innerHTML = addLi(noResultText);}else{doc.innerHTML = LBList;} } } }; xhr.send(null); } if(path == '/' || RegExp('\/search','i').test(path) // || RegExp('_archive.html','i').test(path) || RegExp('\/post-preview','i').test(path) || RegExp('\/layout-preview','i').test(path) ){ doc.innerHTML = addLi(notSearchText); }else{ doc.innerHTML = addLi(loadingText); getJson(1,1); } // --> </script>
Ajaxだの正規表現だの、ほぼ初見の状態から作り始めた。正規表現関連では、返値がときに特殊な内容の配列なため、掲示板等でアドバイスを受けてなんとかなった。フィードデータ読み込み確認に関するonreadystatechangeは、複数回設定したとき、予約されるのではなく上書きされることが解らず、再帰呼出の形に辿りつくのにかなり骨が折れた。
JSONデータを処理するには、その構造を知る必要がある。視覚的にその内容を確認するのに、JSON Viewerを使った。現在のバージョンは、1.2.0.0。JSONデータをこのアプリに食わせると、ツリー状に表示されて、どこに何が入っているのか見やすくなる。
bloggerのフィードデータは、一度に受け取れる最大の500件のときとそれ以外とで、構造が一部変わる。こういったビューワで見ないと気づかない。
0 件のコメント:
コメントを投稿
.