Yukihy Life

ゆきひーによる日常生活をアウトプットするブログ 映画・TOEIC・教育ネタとだいぶ物理とWeb制作

はてなブログで同じカテゴリの記事をランダム順に表示して関連記事っぽいものを作るカスタマイズ

スポンサーリンク

  • 2015/11/11追記1:うまく取得できているかの判断が曖昧だったので、確認方法を追記しました。設置をする際は、うまく取得できているかの確認をお願いします。またCSSをテーマによる崩れを防ぐために若干変更しました。
  • 2015/12/06追記2:数日前に、このプログラムで使用しているGoogle Feed APIのサービスが終了してしまいました。なので表示が安定しない状況です。ただいま代替案を模索中です。お手数おかけしますm(_ _)m
  • 2016/3/20追記3:GoogleFeedAPIが復活?しているみたいできちんと表示されるようになりました!

前回書いた、はてなブログで記事と同じカテゴリを新着順に並べて関連記事っぽくするカスタマイズの続きで、同じカテゴリをランダムに出すのができたので書きたいと思います。

先に言っておきますが、Javascriptを勉強したての者が作っていますので、いろんなテーマや既存のプラグインと干渉して不具合が生じる可能性があります。やる場合は以前のコードをメモ帳にコピペしておくなどバックアップを取っておくようにしてください。

実装図と仕様

実装図

実際に設置してみた感じはこんな感じです。

PC版

f:id:ftmaccho:20151110204930p:plain

スマホ版

f:id:ftmaccho:20151110205032p:plain

以前書いた記事ではスマホ版でうまくいかないという報告があり(このブログはレスポンシブなので気づけませんでした)、その原因を突き止めるのにめちゃくちゃ時間がかかってしまいました。今回は多分うまくいくと思います。

仕様

仕様を簡単に説明すると

  • 今開いている記事の1つ目のカテゴリを含む記事が表示される(2つ目以降のカテゴリは完全に無視される)
  • 1つ目のカテゴリを含む記事を過去30記事分取得して、その中からランダムで表示される
  • 1つ目のカテゴリの記事が他にない場合は、「関連記事はありません」と表示される

といった感じです。はてなのFeedの関係上、同じカテゴリの過去30記事分しか遡ることができません。

例えば僕のブログで言えば、カテゴリ「Web制作」の記事がこの記事で38記事目になりますが、新しい30記事分しか遡ることができないため前にある8記事分はどうあがいても表示することができないということです。

多分これが最大のデメリットだと思うので、ご承知ください。

ただカテゴリを細分化して1つ目のカテゴリをより狭い枠にするなどの工夫を行えば、ある程度は解消されると思います。仕様が単純なのでコントロールもしやすいと思います。

デメリットは他にも

  • サムネイル画像は記事の1番上に設定した者に固定されてしまう

などがあります。

カスタマイズ

では実際のカスタマイズです。PC版とスマホ版で分けています。レスポンシブの方はPC版のみで大丈夫です。

PC版

CSS

最初にCSSです。レスポンシブ対応済みのコードはこんな感じ。

/*関連記事*/
#related-post-title{
    text-align: center;
    margin-top: 10px;
}
#related-post-title-text{
    font-size: 120%;
    font-weight: bold;
}
#related-post-title a{
    color: blue;
    font-size: 80%;
}
.related-post-content{
    display: inline-block;
    width: calc(50% - 20px);
    padding: 10px;
    vertical-align: top;
    border-top: 1px solid #e4e4e4;
}
.related-post-content a{
    display: block;
    width: 100%;
    height: 100%;
    text-decoration: none;
}
.related-post-content img{
    float: right;
    height: 80px;
    width: 80px;
    margin: 10px;
}
.related-post-content .related-post-entrytitle{
    font-size: 16px;
    margin-top: 0;
    margin-bottom: 5px;
    font-weight: bold;
    color: #333;
}
.related-post-content .related-post-date{
    font-size: 10px;
    margin-bottom: 10px;
    color: #444;
}
.related-post-content .related-post-snippet{
    font-size: 10px;
    margin: 0;
    color: #444;
}
@media screen and (max-width:680px){
.related-post-content{
    width: calc(100% - 20px);
}
}

これを「デザインCSS」に。この時点では、まだ何も変わりません。

HTML

次はHTMLです。

<!--関連記事-->
<div id="related-post"></div>

これを関連記事を入れたいところにコピペしてください。一般的には「記事下」でしょうか。

Javascript

最後にJavascriptです。コードは少し長いですが下のとおりです。

<!--関連記事 CopyRight http://www.yukihy.com-->
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
google.load("feeds", "1"); 
function initialize(){
    var blogUrl = "http://www.yukihy.com", //ブログのURL
        num = 6, //表示する記事の数
        maxSubString = 120, //記事の概要の最大文字数
        title = "関連記事", //タイトルの文字
        noTitle = "関連記事はありません", //同じカテゴリが無いときのタイトルの文字
        breadcrumb = 1; //パンクズを導入していない1 導入している2に 2の方は、パンクズのコードよりも下にコピペしてください
    var presentCategory = $("div.entry-categories a:nth-child(" + breadcrumb + ")").text(),
        feed = new google.feeds.Feed(blogUrl + "/feed/category/" + presentCategory), 
        archiveUrl = blogUrl + "/archive"
        presentCategoryUrl = archiveUrl + "/category/" + presentCategory;
    feed.setNumEntries(30); 
    feed.load(dispfeed);
    function dispfeed(result){
        var presentUrl = location.href;
        var container = document.getElementById("related-post"); 
        var feedLength = result.feed.entries.length
        if(!result.error && feedLength == 1 && result.feed.entries[0].link == presentUrl){
            container.innerHTML = '<div id="related-post-title"><span id="related-post-title-text">' + noTitle + '</span>(<a href="' + archiveUrl  + '" target = "_blank"><i class="blogicon-tag"></i>記事一覧へ</a>)</div>'; //挿入するタイトルのHTML
        }else if(!result.error){
            container.innerHTML = '<div id="related-post-title"><span id="related-post-title-text">' + title + '</span>(<a href="' + presentCategoryUrl  + '" target = "_blank"><i class="blogicon-tag"></i>' + presentCategory + 'の記事一覧へ</a>)</div>'; //挿入するタイトルのHTML
            function randomMake(count){
                var randomMakeArray = new Array();
                var randomMakeCount = randomMakeArray.length;
                for(var i = 0 ; i < count; i++){
                    var randomMakeNumber = Math.floor(Math.random() * count);
                    for(var j = 0; j < randomMakeCount; j++) {if(randomMakeArray[j] == randomMakeNumber){randomMakeNumber = Math.floor(Math.random() * count);j= -1;}}
                    randomMakeArray[i] = randomMakeNumber;randomMakeCount++;
                }
                return randomMakeArray;
            }
            randomArray = randomMake(feedLength)
            for (var i = 0; i < num; i++ ){
                var number = randomArray[i];
                var entry = result.feed.entries[number];
                var entryDate = new Date(entry.publishedDate); 
                var entryYear = entryDate.getYear();
                if (entryYear < 2000){entryYear += 1900;}
                var entryMonth = entryDate.getMonth() + 1;
                if (entryMonth < 10) {entryMonth = "0" + entryMonth;}
                var entryDay = entryDate.getDate();
                if (entryDay < 10) {entryDay = "0" + entryDay;}
                var date = entryYear + "/" + entryMonth + "/" + entryDay;
                var entryImg = "";
                var imgCheck = entry.content.match(/(src="http:)[\S]+((\.jpg)|(\.JPG)|(\.jpeg)|(\.JPEG)|(\.gif)|(\.GIF)|(\.png)|(\.PNG))/); //画像のチェック
                entryImg += '<img ' + imgCheck[0] + '" >';
                if(entry.link != presentUrl){
                    container.innerHTML += '<div class="related-post-content"><a href="' + entry.link  + '" target = "_blank">' + entryImg + '<p class="related-post-date">'  + date  + '</p><h3 class="related-post-entrytitle">' + entry.title + '</h3>' + '<p class="related-post-snippet">' + entry.contentSnippet.substring(0,maxSubString) + '</p></a></div>' //挿入する関連記事のHTML
                }else{
                    num ++ 
                }
            }
        }
    }
}
google.setOnLoadCallback(initialize);
</script>

これを「フッター」に入れた後、以下の設定をしてください。

最後に調整

最後に今コピペしたJavascriptの中身を、各自のブログで変えていただきます。変えるのは7~12行目のところです。

  • blogUrl = "http://www.yukihy.com",  → ここに各自のブログURLを入れてください
  • num = 6,  → 表示する記事の数になります
  • maxSubString = 120,  → 記事の概要部分のの最大文字数です いらない方は0に
  • title = "関連記事",  → タイトルの文字です
  • noTitle = "関連記事はありません",  → 同じカテゴリの記事が無いときのタイトルの文字です
  • breadcrumb = 1; → パンクズリストを設定している方は2にしてください(もしうまくいかない場合はここの数字を1に戻したりしてみてください^^;)

以上が設定になります。

パンクズリストを設定している方は、フッターに貼ってあるパンクズリストのコードよりも下にJavascriptを貼り付けるようにしてください。読み込みの順番の関係で、不具合が生じる可能性があります。

以上で完成です!

スマホ版

ここからはスマホ版のカスタムです。

HTML & CSS

スマホ版はHTMLとCSSを一気に貼り付けてしまいます。

<!--関連記事-->
<div id="related-post"></div>

<style type="text/css">
/*関連記事*/
#related-post-title{
    text-align: center;
    margin-top: 10px;
}
#related-post-title-text{
    font-size: 120%;
    font-weight: bold;
}
#related-post-title a{
    color: blue;
    font-size: 80%;
}
.related-post-content{
    display: inline-block;
    width: calc(100% - 20px);
    padding: 10px;
    vertical-align: top;
    border-top: 1px solid #e4e4e4;
}
.related-post-content a{
    display: block;
    width: 100%;
    height: 100%;
}
.related-post-content img{
    float: right;
    height: 80px;
    width: 80px;
    margin: 10px;
}
.related-post-content .related-post-entrytitle{
    font-size: 16px;
    margin-top: 0;
    margin-bottom: 5px;
    color: #333;
    font-weight: bold;
}
.related-post-content .related-post-date{
    font-size: 10px;
    margin-bottom: 10px;
    color: #444;
}
.related-post-content .related-post-snippet{
    font-size: 10px;
    margin: 0;
    color: #444;
}
</style>

これを自分が表示したい場所に貼り付けてください。一般的には「記事下」でしょうか。

Javascript

最後にJavascriptです。コードは以下。

<!--関連記事 CopyRight http://www.yukihy.com/-->
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
google.load("feeds", "1"); 
function initialize(){
    var blogUrl = "http://www,yukihy.com", //ブログのURL
        num = 6, //表示する記事の数
        maxSubString = 120, //記事の概要の最大文字数
        title = "関連記事", //タイトルの文字
        noTitle = "関連記事はありません"; //同じカテゴリが無いときのタイトルの文字
    var presentCategory = $("div.categories a:nth-child(2)").text(),
        feed = new google.feeds.Feed(blogUrl + "/feed/category/" + presentCategory), 
        archiveUrl = blogUrl + "/archive"
        presentCategoryUrl = archiveUrl + "/category/" + presentCategory;
    feed.setNumEntries(30); 
    feed.load(dispfeed);
    function dispfeed(result){
        var presentUrl = location.href;
        var container = document.getElementById("related-post"); 
        var feedLength = result.feed.entries.length
        if(!result.error && feedLength == 1 && result.feed.entries[0].link == presentUrl){
            container.innerHTML = '<div id="related-post-title"><span id="related-post-title-text">' + noTitle + '</span>(<a href="' + archiveUrl  + '" target = "_blank"><i class="blogicon-tag"></i>記事一覧へ</a>)</div>'; //挿入するタイトルのHTML
        }else if(!result.error){
            container.innerHTML = '<div id="related-post-title"><span id="related-post-title-text">' + title + '</span>(<a href="' + presentCategoryUrl  + '" target = "_blank"><i class="blogicon-tag"></i>' + presentCategory + 'の記事一覧へ</a>)</div>'; //挿入するタイトルのHTML
            function randomMake(count){
                var randomMakeArray = new Array();
                var randomMakeCount = randomMakeArray.length;
                for(var i = 0 ; i < count; i++){
                    var randomMakeNumber = Math.floor(Math.random() * count);
                    for(var j = 0; j < randomMakeCount; j++) {
                        if(randomMakeArray[j] == randomMakeNumber){
                            randomMakeNumber = Math.floor(Math.random() * count);
                            j= -1;
                        }
                    }
                    randomMakeArray[i] = randomMakeNumber;
                    randomMakeCount++;
                }
                return randomMakeArray;
            }
            randomArray = randomMake(feedLength)
            for (var i = 0; i < num; i++ ){
                var number = randomArray[i];
                var entry = result.feed.entries[number];
                var entryDate = new Date(entry.publishedDate); 
                var entryYear = entryDate.getYear();
                if (entryYear < 2000){
                    entryYear += 1900;
                }
                var entryMonth = entryDate.getMonth() + 1;
                if (entryMonth < 10) {
                    entryMonth = "0" + entryMonth;
                }
                var entryDay = entryDate.getDate();
                if (entryDay < 10) {
                    entryDay = "0" + entryDay;
                }
                var date = entryYear + "/" + entryMonth + "/" + entryDay;
                var entryImg = "";
                var imgCheck = entry.content.match(/(src="http:)[\S]+((\.jpg)|(\.JPG)|(\.jpeg)|(\.JPEG)|(\.gif)|(\.GIF)|(\.png)|(\.PNG))/); //画像のチェック
                entryImg += '<img ' + imgCheck[0] + '" >';
                if(entry.link != presentUrl){
                    container.innerHTML += '<div class="related-post-content"><a href="' + entry.link  + '" target = "_blank">' + entryImg + '<p class="related-post-date">'  + date  + '</p><h3 class="related-post-entrytitle">' + entry.title + '</h3>' + '<p class="related-post-snippet">' + entry.contentSnippet.substring(0,maxSubString) + '</p></a></div>' //挿入する関連記事のHTML
                }else{
                    num ++ 
                }
            }
        }
    }
}
google.setOnLoadCallback(initialize);
</script>

これを「フッター」にコピペした後、以下の設定をお願いします。

最後に調整

PC版と同じように、変えるのは7~12行目のところです。

  • blogUrl = "http://www.yukihy.com",  → ここに各自のブログURLを入れてください
  • num = 6,  → 表示する記事の数になります
  • maxSubString = 120,  → 記事の概要部分のの最大文字数です いらない方は0に
  • title = "関連記事",  → タイトルの文字です
  • noTitle = "関連記事はありません",  → 同じカテゴリの記事が無いときのタイトルの文字です

スマホ版にはパンクズによる調整は大丈夫だと思います。

以上でカスタマイズ終了です!

うまく取得しているか、していないかの判断方法

上のコードだと、記事がうまく取得できているかできたいないかが凄く判断し辛いことが分かりました^^;

コードを設置した後、うまく取得できているかの判断方法を書いておくので、一応確認をお願いします。

うまく取得している例

f:id:ftmaccho:20151111145615p:plain

うまく取得しているかは、上の画像のようにそのカテゴリの文字(上の例で言うと「デモやん」)が出ているかで確認をしてください。

f:id:ftmaccho:20151111145028p:plain

例えば上の画像は関連記事が表示されていませんが、「デモ」という文字がしっかりと取得できています。これはプログラムは合っているので、そのままにしていただいてOKです。

おそらく過去記事が公開されていなかったり、記事の変更がFeedに反映されていないがために起こることです。

うまく取得できていない例

うまく取得できていない例として、例えば下の図のようなもの。

f:id:ftmaccho:20151111145942p:plain

上の画像は記事は表示されていますが、「〜の記事一覧へ」の「〜」が取得されていません。

この状態はプログラムがうまく機能しておらず、表示されている関連記事はただ新しい記事を引っ張ってきているだけです。よくよく見ると、カテゴリが違うのも表示されていると思います。

この状態の原因は数点あります。

  1. 記事にカテゴリを設定していない
  2. パンクズリストを設置しているのにJavascriptのパンクズのところを1にしている
  3. パンクズリストのコードよりもJavascriptが上に設置されている
  4. ブログのテーマによる違い
  5. その他良くわからない

などなどが考えられます。

対処法としては1~3はそのまま上までの中に説明があるのでお願いします。

4・5に関しては、対処法を書くと、

Javascriptの13行目の

var presentCategory = $("div.entry-categories a:nth-child(" + breadcrumb + ")").text(),

の部分を

var presentCategory = $("div.entry-categories a:nth-child(2).text(),

など、カッコ内を半角数字にして1,2などを順番に入れてみてください。多分どこかの数字でうまいこと表示されるようになると思います。^^;

生成されるHTML

デザインを変更したい方もいると思うので、生成されるHTMLの構造を簡単に書いておきます。だいたいこんな感じです。

f:id:ftmaccho:20151110213114p:plain

<div id="related-post">
    <div id="related-post-title">
        <span id="related-post-title-text">関連記事</span>(
        <a href=""><i class="blogicon-tag"></i>Web制作の記事一覧へ</a>)
    </div>
    <div class="related-post-content">
        <a href="">
            <img src="">
            <p class="related-post-date">2015/06/20</p>
            <h3 class="related-post-entrytitle">はてなブログシェア数付きSNSボタン〜</h3>
            <p class="related-post-snippet">7/5追記1:コピペコード2〜</p>
        </a>
    </div>
</div>

複数記事があると、

    <div class="related-post-content">
        <a href="">
            <img src="">
            <p class="related-post-date">2015/06/20</p>
            <h3 class="related-post-entrytitle">はてなブログシェア数付きSNSボタン〜</h3>
            <p class="related-post-snippet">7/5追記1:コピペコード2〜</p>
        </a>
    </div>

の部分が複数生成されるような感じです。

HTML5からはaタグでブロック要素も囲んで良いので、そうしています。これによってリンクの位置が広くなり、クリックしやすくなっています。

まとめ

以上がカスタマイズになります!

正規品でなく、技術不足であるので思わぬ不具合が生じる可能性があります。もしうまくいかない場合は声をかけていただけると嬉しいです。直せないかもしれませんが^^;

質問や設置代行・ブログカスタム依頼などは、お問い合わせ - Yukihy Lifeよりお願いいたします!

関連記事

www.yukihy.com

カスタマイズまとめ記事

www.yukihy.com