ガジェット追加で関連記事の自動表示をさせる方法


記事の終わりに関連記事が表示されると、興味を持って他の記事も読んでもらえるチャンスにつながります。

関連記事の自動表示は、レイアウトのガジェット追加で設置することができるので挑戦してみましょう!

ガジェット追加のHTMLを用いるので、HTML入門にも良いかもしれません。


ガジェット追加で関連記事の自動表示をさせる方法

コード元様

以下のブログのコードを使用します。


参考ブログ様

Under construction【Blogger で関連記事を表示したい。】


コードについては自分が解説するより、上記のブログを見て頂いた方が分かりやすいと思います。


自分が実際に試してみたコード

当ブログは現在はHTMLで関連記事を表示させていますが、実際に試したものをご紹介します。

長いですが、コメントアウトで日本語説明加えているので参考にしてみてください。


<style type="text/css">
.related-posts {
  margin-top: 20px;
  margin-bottom: 20px;
  border-top: 1px solid ; /*上線*/
  border-bottom: 1px solid  ; /*下線*/
}
  .related-posts-title {
    text-align: center; /*関連記事中央寄せ*/
    font-size: 20px; /*関連記事文字サイズ*/
    font-weight: bold; /*関連記事太文字*/
    padding-top: 20px;
    padding-bottom: 5px;
  }
  .related-posts-body {
    overflow-wrap: break-word;
    word-wrap: break-word;
  }
    /* ul */
    .related-posts-list-items {
      display: flex;
      flex-wrap: wrap;
      justify-content: space-between;
      list-style: none;
      padding: 0;
      padding-bottom: 10px;
    }
    /* li */
    .related-posts-item {
      flex-shrink: 0;
      min-width: 0;
      width: 240px; /*画像幅*/
      overflow-wrap: break-word;
      word-wrap: break-word;
      text-align: center;
      transition: .3s box-shadow cubic-bezier(.4,0,.2,1);
      margin-top: 20px;
    }
    .related-posts-item:hover {
      opacity: .8;
      box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.2)
    }
    @media (max-width: 768px) {
      .related-posts-item {
        max-width: 240px; /*画像幅*/
        width: 100%;
        margin-left: 0;
      }
    }
    .related-posts-item-link {
      text-decoration: none;
      display: block;
      width: 100%;
      height: 100%;
    }
    .related-posts-item-text {
      text-align: center; /*記事タイトル中央寄せ*/
      padding: 0 10px;
      color:  ;/*記事タイトル色*/
      font-size: 0.9em; /*記事タイトル文字サイズ*/
    }
    .related-posts-item-date {
      text-align: end; /*日付末右寄せ*/
      color:  ; /*日付文字色*/
      font-size: 0px; /*日付文字サイズ*/
    }
</style>
<script>
  /**
   * 設定 ここから
   */
  // 関連記事の最大表示数
  const maxRelatedPosts = 3;
  // ラベル要素を取得するためのCSSセレクター(テーマによってはセレクターが違う場合があると思われ)
  const labelSelector = '.post-labels > a';
  // 関連記事のリストのタイトル
  const relatedPostsTitle = '関連記事';
  // 追加する要素のセレクター
  const targetSelector = '.post';
  // 実行するまでの遅延(1000は一秒)
  // (遅延する意味は無いけど非同期で実行されていることが確認できる)
  const delayTime = 1000;
  /**
   * 設定 ここまで
   */
  // 現在のページのホストからパスまで example.com/path/to/index.html
  const uri = `${location.hostname}${location.pathname}`;
  // 現在のページと同じURLかどうかを確認する正規表現
  const reCurrentPageURL = new RegExp(
    `https?:\\/\\/${uri.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&')}`
  );
  function parseJson(json) {
    const items = [];
    for (const entry of json.feed.entry) {
      for (const link of entry.link) {
        if (!('rel' in link) || !('type' in link) || !('href' in link)) {
          continue;
        }
        if (link.rel != 'alternate' || link.type != 'text/html') continue;
        if (reCurrentPageURL.test(link.href)) continue;
        const item = {
          href: link.href,
          title: entry.title?.$t,
          summary: entry.summary?.$t,
          published: entry.published?.$t,
          updated: entry.updated?.$t,
          thumbnail:            'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPoAAACWBAMAAAAF9IgvAAAAElBMVEXLy8v+/v7Jycnv7+/W1tbh4eG0JFuyAAAFfElEQVR42u1ZTWOrOAx0HHqv1sldK8i9Ds0dSHrP5///K29kCCENDfS9ffSwnlMhkLGk0chxjYmIiIiIiIiIiIiIiIiIiIiIiIiIiIiI+FFYy/xwj6ejZ/l0A9d2uvAfYw8r+CmITBW8PDArN09WdmuH1/S3kCS7R/BUwZf0iKX9SXbHj30gI9cj31m3fWB3/exmdBd+p1tLyj/jC/bRUvwW+5GlAyNZf+b/e+qGHa/Ylt3wV7H/FdUdRfhWK/4i9s/15BF1r6N5zr63NrlUHdGOin1MhsewH23iadOZrn3sFp20G9FZd8+NY9+Sq27zPgF7bb4rOuLaHhZYTXJAJ1ZF/dB2yaZ0GIVY5RzvgjL1FbN65IcnTSduKPIlP+tAZT/Qm9zYTcs+p1eVhF+IDa7kFk3AJZ6YYWkgl4Mv9PtLWuPS2jR4RsGSNr4pQ7EfqOK+2FP9i62yJ0RqBEX4QA6OZUavys6eKrAKIgiJ9+RORO9WVjX7xrJ9zu7p9kQndo0D6UTmBWl4l2xLb/UHYOcZLbEn40yfAb1OB8O4dEawfuE57fXZ3VN9hthdl70bO60zY8AOQ67YZiBs2UulMDInKlhf8g7dyim94eqAe6m2srqXDMQ+x8NfxA66ELtHoNaA9cqOzGNBgvJTERZ6ctA7MlIlbFZng9iPtX8M1Z39W9YfOxSBkkJsqj/Bw3VvHILqoDMNk5TjX3rBF6kejUGWjKouxM5PN2nKnmX7vrqDfU5rqA5x00L3mrMQp6pOuHT0ChH6nAp0ZelWEEWCrIitzSKtYzfMA+z2uqtGfNjet26TkvELrkLs/+g0SFt2ZN6VTooVnahIwgppof3nMouZgR5c0V4Gh33IvC0aj5cNUntlR90rMKDjruzzG7uduRnBU2iLe9b618w71ZvTOaVen9JZN2nD7FdtMIT6LqYTe5VqQ/axS0mwQtaMgz2DX6HkYjTz2eVyOV7dZphdGltneAXdJixiNwktRDWv7Nxl55nL/CtWtoIwM3ygmQrsBnqEBkazo9pti6F6ndgL613DrtmZ3bHjA0PrFPlH+xl+0Z2Csm/xLWt43SbPT5cRmedG5Ifg0V3V4Xsb1Ukw/lvdoQhN+zFVH9ImQPbrume7D9ju1W2G2TM611NFse+yQ7rvvbFDdSgtaq19gAydTjmKFJahMlhDQns7+IMs1L2kpSbe37Pb0GB+2bJzh93MHGcOXgjVgU2hotd1VVCLZv4oo3ZWGGAwMdtMpbvYLR8celkwXDHuytppm9jR5bBA1XzzptNBDPeQF1rbxm3skNNKWc9h38POOinBfHD6g8+7O9XBZvfIcIVBob29Bd9MJ5vMw4qOw0cRYF8F2uqFHtlBluVYmejWF6pe8K3fg9er3xT6N0q8gvGvUHydA7ZVHfPzvQ1CB7/zPeyoB/YNC4HA3HnnIabgC7XmEdaOQ1uG2WfDKMJzxVZHf0obuM7lLM/Zzw1tH3uBN1O3wCbCh59Y9RdxU/dgEyk2PPTK2rV+Kc3vwr3h687KPq/76dMPuZYdAevGIcN8MybU5a0ZWJpZ7CqDTSFBGYLGeEJBwjKxnRKd73/GDsOG1JLqvNdue8nzc+NK8nGWIvvgcMCS7UxyCWLkFbZRNjnlG2wqJbuc68z/Jns4wMHkqM8SxLTGhVs6Q7GDxkxm3VDpYMZSkAqdr7pY3Ar7ebH2d9nvvWrkkYJtV2llaML3sS95qoObki73hwf1lLFTsR/lDroll+lid961hyb4y3t13cli7zs14p88s/reydMf4ON0yTcd5Cd1lalOibkxhTvhTXgezQ/skx6Hy6d/FrCZkn5Sth87Do+IiIiIiIiIiIiIiIiIiIiIiIiIiIiI+H/iF/5oF83c0tPeAAAAAElFTkSuQmCC',
        };
        if ('media$thumbnail' in entry) {
          item.thumbnail = entry.media$thumbnail.url.replace(
            /([=/])s72-[^/&]+/,
            '$1w240-h120-n'
          );
        }
        items.push(item);
        break;
      }
    }
    return items;
  }

  function getDateFormattedString(dateString) {
    const date = new Date(dateString);
    const yyyy = date.getFullYear();
    const mm = String(date.getMonth() + 1).padStart(2, '0');
    const dd = String(date.getDate()).padStart(2, '0');
    return `${yyyy}-${mm}-${dd}`;
  }
  function createRelatedPostsListItem(item) {
    /* item {
      href: string;
      title: string;
      summary: string;
      published: string;
      updated: string;
      thumbnail: string;
    } */
    const li = document.createElement('li');
    li.className = 'related-posts-item';
    const link = document.createElement('a');
    link.className = 'related-posts-item-link';
    link.href = item.href;
    const img = document.createElement('img');
    img.className = 'related-posts-item-image';
    img.src = item.thumbnail;
    img.alt = item.title;
    img.title = item.title;
    img.width = '240';
    img.height = '120';
    const div = document.createElement('div');
    div.className = 'related-posts-item-text';
    const title = document.createElement('p');
    title.className = 'related-posts-item-title';
    title.innerText = item.title;
    div.appendChild(title);
    const date = document.createElement('p');
    date.className = 'related-posts-item-date';
    date.innerText = getDateFormattedString(
      item.updated ? item.updated : item.published
    );
    div.appendChild(date);
    link.appendChild(img);
    link.appendChild(div);
    li.appendChild(link);
    return li;
  }
  function createRelatedPosts(items) {
    const divRelatedPosts = document.createElement('div');
    divRelatedPosts.className = 'related-posts';
    const divTitle = document.createElement('div');
    divTitle.className = 'related-posts-title';
    divTitle.innerText = relatedPostsTitle;
    const divBody = document.createElement('div');
    divBody.className = 'related-posts-body';
    const ul = document.createElement('ul');
    ul.className = 'related-posts-list-items';
    items.forEach((item) => {
      const li = createRelatedPostsListItem(item);
      ul.appendChild(li);
    });
    divRelatedPosts.appendChild(divTitle);
    divRelatedPosts.appendChild(divBody);
    divBody.appendChild(ul);
    return divRelatedPosts;
  }
  function responsesToJson(responses) {
    return Promise.all(responses.map((response) => response.json()));
  }
  function failure(error) {
    console.log(`${error.message}`);
  }
  // 引数の data は JSON の配列
  function success(data) {
    let items = [];
    for (const json of data) {
      const item = parseJson(json);
      // マージして重複を除く
      items = [...items, ...item].filter((item, index, array) => {
        return array.findIndex((i) => i.href === item.href) === index;
      });
    }
    if (items.length == 0) return;
    const relatedPosts = createRelatedPosts(
      // slice の範囲指定は配列の要素の個数よりも最大数(maxRelatedPosts)が大きくてもエラーにはならない
      items.sort(() => Math.random() - 0.5).slice(0, maxRelatedPosts)
    );
    const targetElement = document.querySelector(targetSelector);
    if (!targetElement) return;
    targetElement.appendChild(relatedPosts);
  }
  // ページのラベルを取得
  function getLabels() {
    const labels = [];
    const re = /\/search\/label\/([^\/]+)/;
    const list = document.querySelectorAll(labelSelector);
    for (const a of list) {
      const m = re.exec(a.href);
      if (!m) continue;
      labels.push(m[1]);
    }
    return labels;
  }
  function handleEvent() {
    new Promise((resolve, reject) => {
      setTimeout(() => {
        const labels = getLabels();
        if (!labels.length) return;
        const hostname = location.hostname;
        const maxResults = 30;
        const promises = [];
        // 以下のドキュメントには "|" で OR、"," で AND と書かれている。
        // https://developers.google.com/gdata/docs/2.0/reference?hl=ja#Queries
        // "label1|label2" のようにすると、それぞれのラベルを持つ記事が取得できるはずだけど、
        // 機能しなかったのでループを回してラベルごとにリクエストを送る必要がある。
        for (const label of labels) {
          const rawUrl = `https://${hostname}/feeds/posts/default?alt=json&category=${encodeURIComponent(label)}&max-results=${maxResults}`;
          try {
            const promise = fetch(rawUrl);
            promises.push(promise);
          } catch (error) {
            console.error(error.message);
          }
        }
        Promise.all(promises)
          .then(responsesToJson)
          .then(success)
          .catch(failure);
        resolve(null);
      }, delayTime);
    });
  }
  addEventListener('DOMContentLoaded', handleEvent);
</script>


上記のコードを使うと、以下のような関連記事が作成できます。



色はデフォルトで良ければ未記入でOKです。

日付を削除しているので、必要なら文字サイズを入力してください。

文字サイズや画像幅など、数値をいじって試してみてくださいね。


ガジェット追加方法

左のメインメニューから【レイアウト】を選択し、サイドバーなどにある【ガジェットを追加】をクリックします。

後でページの本文に移動するので、どこの【ガジェットを追加】でも問題ありません。ページの本文に近い位置が移動しやすいと思います。



ガジェットを追加の画面が開いたら、【HTML/JavaScript】を選択します。



【HTML/JavaScript】の設定画面が開いたら、コンテンツに先程のコードを貼り付けます。

タイトルは未記入でOKです。



保存したら、作成した「HTML/JavaScript」ガジェットをドラッグでページの本文に移動します。



これで、関連記事が自動で記事の下に挿入されます!



関連記事を表示して他の記事も見てもらおう!

冒頭でも書きましたが、関連記事が表示されていると興味を持って他の記事も読んでもらえるチャンスにつながります。


また内部リンク(自分のブログ内のページをつなぐリンク)があることで、SEOにも効果があります。

SEOとはSearch Engine Optimizationの略称で、検索エンジンの最適化を意味します。

内部リンクがある事で、このクローラーが自分のブログを巡回しやすくなるんです。


利点が多いので、関連記事を表示させてみてくださいね!


にほんブログ村 ブログブログ ブログサービスへ にほんブログ村 ブログブログ ブログノウハウへ