ぶろぐらまー

Bloggerにページナビゲーションをつけるよ!

ページナビゲーション

ページナビゲーションは、上図のように記事の一覧など1ページに収まらない場合に、複数のページに分けて表示する機能です。

残念ながらBloggerには、このページナビゲーションの機能がありません。前後の記事へのナビゲーションの機能はあるのですが、ページをナビゲーションする機能はありません。

ということで、今回はこのページナビゲーションの機能をJavaScriptで作成してみたいと思います。

まずは、ページナビゲーションを実現するために、必要な情報と実装方法をまとめていきます。

「解説はいらないからソースコードはよ!」という方は、ソースコードまで飛んでください。

ページナビゲーションを実現するために必要な情報

ページナビゲーションを実現するにあたり、まずは必要な情報を洗い出してみます。ざっと挙げてみると以下のような情報が必要ですね。

  • 記事の総数
    • ページの総数を算出するために必要になります。
  • 1ページに表示する記事数
    • これは自分で決める数字です。Bloggerの投稿ページのデフォルトは7ですので、この前後の数字が良いでしょう。
  • ページの総数
    • ページの総数は「記事の総数 ÷1ページに表示する記事数」で求めます。
  • 各ページのURL
    • ページ番号のリンクにつけるURLです。
  • 現在のページ番号
    • 現在表示しているページ番号です。必須ではありませんが、現在表示しているページ番号だけ色を変えたり、「前のページへ」「次のページへ」のような機能をつけたい場合に必要になります。
    • 今回は、現在表示しているページ番号にはリンクをつけないようにします。

記事の総数

ページの総数を算出するために必要になります。すべての記事の情報が必要になるので、「投稿」ガジェットのデータタグなどからの算出も厳しいです。

そこで、JavaScriptでフィード情報をリクエストして取得します。

フィードはRSSなどで使用される情報で、HTMLリクエストで記事の情報を取得できる仕組みを使用します。

これを使用すると、記事の情報をAtomやJsonといった形式で取得ができます。取得にはJavaScriptのfetch()を使ってます。

// フィードURLを作成する。
var feedUrl = blogUrl + 'feeds/posts/summary';
feedUrl += '?orderby=published';
feedUrl += '&max-results=';
feedUrl += maxResults;
feedUrl += '&alt=json';

// フィードを取得する。
fetch(feedUrl)
.then((response) => {
  console.log(feedUrl);

  if(response.ok) {
    return response.json();
  } else {
    throw new Error();
  }
})
.then(function(json) {
  console.log(json);

  // ページ総数を算出する。
  var totalResults = parseInt(json.feed.openSearch$totalResults.$t, 10);

1ページに表示する記事数

これは自分で決める数字です。今回はソースコードにべた書きにしてます。

var maxResults = 7;

ページの総数

ページ番号を表示するには、ページの総数が必要となります。ページの総数がないと、何ページ分のリンクを作ったらよいかわからないためです。

ページの総数は「ページの総数 = 記事の総数 ÷1ページに表示する記事数」で求めることができます。

var totalPage = parseInt(totalResults / maxResults );
if ((totalResults % maxResults ) > 0)
{
   totalPage += 1;
}

表示する記事が1ページに表示する記事数に満たない場合でも、少なくとも1ページは表示するため、2~5行目の処理があります。

各ページのURL

ページナビゲーションを実現するためのキモになります。

各ページへリンクをはって、クリックしたらそのページを表示させる必要があります。

例えば、1ページに7記事表示させるのであれば、「1ページ」をクリックしたら1記事目~7記事目を、「2ページ」をクリックしたら、8記事目~14記事目を表示させます。

これを実現させるために、Blogger検索のURLの仕組みを使います。

URLの仕組み

このブログにある「検索」で「blogger」を検索してみてください。すると「blogger」に関連する記事が一覧で表示されると思います。

その時のURLを見てみてください。下のようになっていると思います。

https://bgt-48.blogspot.jp/search?q=blogger

ブログのドメインの後がsearch?q=bloggerとなっています。「検索」はキーワード検索なので、?q=キーワードの形になっています。このようにURLにパラメータを与えると特定の投稿のみに絞り込むことができます。

上記はキーワードによる記事の絞り込みですが、投稿日時や取得する記事数による絞り込みも可能です。この投稿日時と記事数の絞り込みによって「1記事目~7記事目だけ取得する」「8記事目~14記事目だけ取得する」ということが可能になります。

URLのパラメータ

具体的には、以下のパラメータを使って1ページに表示する記事に絞り込みます。
複数のパラメータを指定する場合は、以下のように&でつなげて指定します。

https://bgt-48.blogspot.jp/search/?orderby=published&max-results=7&updated-max=2018-01-09T21%3A00%3A00%2B09%3A00
  • orderby
    • publishedを指定します。これによって投稿日順に表示されます。
  • updated-max
    • 表示する投稿の一番新しい日付をしていします。日付のフォーマットは、RFC3339の形式(例:‘2005-08-09T10:57:00+09:00’)です。これを指定すると、この日付までの投稿が表示されます。
    • 日付は、フィード情報から取得します。
  • max-result
    • 検索結果の最大数を指定します。1記事目~7記事目であれば最大7記事取得したいので7になります。

ちょっとわかりづらいですね。例をあげましょう。

以下のような10個の記事があったとします。これを1ページに5記事ずつ表示したいとします。

No 投稿日時
1 2019-01-01 12:00:00
2 2019-01-11 12:00:00
3 2019-01-21 12:00:00
4 2019-01-31 12:00:00
5 2019-02-01 12:00:00
6 2019-02-11 12:00:00
7 2019-02-21 12:00:00
8 2019-03-01 12:00:00
9 2019-03-11 12:00:00
10 2019-03-21 12:00:00

1ページに5記事ずつ表示したいわけですので、1ページ目に表示する記事はNo1~5、2ページ目に表示する記事はNo6~10です。

No.1~5で一番新しい記事の投稿日時は「2019-01-01 12:00:00」ですので、この投稿日時までの5記事分を表示させればよいですね。

なので1ページ目のURLは以下のようになります。

https://bgt-48.blogspot.jp/search/?orderby=published&max-results=5&updated-max=2019-01-01T12%3A00%3A00%2B09%3A00

同様に2ページ目のURLは以下のようになります。

https://bgt-48.blogspot.jp/search/?orderby=published&max-results=5&updated-max=2019-02-11T12%3A00%3A00%2B09%3A00

ここで問題なのがupdate-maxパラメータになります。update-maxパラメータに、そのページに表示する投稿の一番新しい日付を指定しますが、実際にどうやって求めればよいのでしょうか?

これについては、次で説明します。

各ページ内で最新投稿の日付の取得方法

ページ内の最新の投稿の日付はフィード情報から取得します。

フィード情報を1ページに表示する件数分だけ取得し、そのフィード情報の中から最新の投稿の日付を取得します。

これを、ページ数分だけ繰り返すことで、各ページ内で最新の投稿の日付を取得することができます。

ソースコード

おまたせしました。ソースコードです。
上の解説をみながら、ソースを読んでみてください。

<!-- pager -->
<b:if cond='data:blog.pageType == &quot;index&quot;'>
  <div class='blogger-pager'></div>

  <script type='text/javascript'>var blogUrl = &quot;<data:blog.homepageUrl/>&quot;</script>
  <script type='text/javascript'>var label = &quot;<data:blog.searchLabel/>&quot;</script>
  <script type='text/javascript'>
    //<![CDATA[
    var selector = '.blogger-pager';
    var maxResults = 7;

    insertPagerLink(selector, maxResults);

    //
    // 指定したセレクタにページナビゲーションを挿入する
    //
    function insertPagerLink(selector, maxResults)
    {
      // フィードURLを作成する。
      var feedUrl = blogUrl;
      feedUrl += 'feeds/posts/summary';
      feedUrl += '?orderby=published';
      feedUrl += '&max-results=';
      feedUrl += maxResults;
      feedUrl += '&alt=json';

      // フィードを取得する。
      fetch(feedUrl)
        .then((response) => {
          console.log(feedUrl);

          if(response.ok) {
            return response.json();
          } else {
            throw new Error();
          }
        })
        .then(function(json) {
          console.log(json);

          // URLからカレントのページ番号を算出する。
          var currentUrl = location.href;
          var currentPage = 1;
          if (currentUrl.indexOf("#Page-") > -1)
          {
            var no = currentUrl.substring(currentUrl.indexOf("#Page-")+6);
            currentPage = parseInt(no);
          }
          console.log('currentPage=' + currentPage);

          // ページ総数を算出する。
          var totalResults = parseInt(json.feed.openSearch$totalResults.$t, 10);
          var startIndex = parseInt(json.feed.openSearch$startIndex.$t, 10);
          var itemsPerPage  = parseInt(json.feed.openSearch$itemsPerPage.$t, 10);

          var totalPage = parseInt(totalResults / maxResults );
          if ((totalResults % maxResults ) > 0)
          {
             totalPage += 1;
          }
          console.log('totalPage=' + totalPage);

          // ページナビゲーションを作成する。
          var pager = '';
          for (i = 1; i <= totalPage; ++i)
          {
            if (i == currentPage) {
              pager += '<span class="current-page">' + i + '</span>';
            }
            else {
              pager += '<a id="Page-' + i + '"' + ' href=""><span class="page">' + i + '</span></a>';
            }
          }

          // HTMLへ書き出す。
          var pagerElem = document.querySelector(selector);
          if (null != pagerElem)
          {
            pagerElem.innerHTML = pager;
          }

          // ページナビゲーションにURLを設定する。
          for (i = 1; i <= totalPage; ++i)
          {
            if (i == currentPage) continue;

            setTargetPageUrl(selector, blogUrl, label, i, maxResults);
          }
        })
        .catch((error) => {
          console.log(error)
        });
    }

    //
    // 指定したページのURLを設定する
    //
    function setTargetPageUrl(selector, blogUrl, label, targetPage, maxResults)
    {
      var href = blogUrl;

      // 指定したページのインデックスを算出する。
      // インデックスは1開始なので、0以下の場合は1とする。
      var startIndex = (targetPage - 1) * maxResults;
      if (startIndex <= 0) startIndex = 1;

      // フィードURLを作成する。
      var feedUrl = blogUrl;
      feedUrl += 'feeds/posts/summary';
      if (label != '')
      {
        // カテゴリページの場合はlabelをつける
        feedUrl += '/-/' + label;
      }
      feedUrl += '?orderby=published';
      feedUrl += '&start-index=';
      feedUrl += startIndex;
      feedUrl += '&max-results=';
      feedUrl += maxResults;
      feedUrl += '&alt=json';

      // フィードを取得する。
      fetch(feedUrl)
        .then((response) => {
          console.log(feedUrl);

          if(response.ok) {
            return response.json();
          } else {
            throw new Error();
          }
        })
        .then(function(json) {
          console.log(json);

          // 一番新しい記事の日付を取得する。
          var date = encodeDate(json.feed.entry[0].published.$t);

          // ページURLを作成する。
          href += 'search';
          if (label != '')
          {
            // カテゴリページの場合はlabelをつける
            href += '/label/' + label;
          }
          href += '?orderby=published';
          href += '&max-results=';
          href += maxResults;
          href += '&updated-max=' + date;
          href += '#Page-' + targetPage;

          // hrefにURLを設定する。
          var liSelector = selector + ' #Page-' + targetPage;
          var liElem = document.querySelector(liSelector);
          if (null != liElem)
          {
            liElem.href = href;
          }
        })
        .catch((error) => {
          console.log(error)
        });
    }

    //
    // 日付をRFC3339タイムスタンプ形式で取得する。
    //
    function encodeDate(dateStr)
    {
      dateStr = dateStr.substring(0, 19) + dateStr.substring(23, 29);
      return encodeURIComponent(dateStr);
    }
    //]]>
  </script>
</b:if>

参考サイト

フィードの取得する際のクエリと取得できるデータのフォーマットについて、Googleのヘルプに詳細があります。こちらも参考にしてください。

Google Data APIs #Queries

Google Data APIs #DocumentFormat

最後まで読んでいただき、ありがとうございます。
また読んでくださいませ。
そんじゃーね。

SPONSORED LINK
SPONSORED LINK