Multi Vitamin & Mineral

Multi Vitamin & Mineral です。プログラムに関することを書いております。

記事のトップに更新日時も表示する【脱jQuery】【脱sitemap.xml利用】【オリジナル】(はてなブログ改造計画)

記事のトップに更新日時も表示する方法です。

すでにたくさんの方が同様の記事を書いていますが、なんやかんやでオリジナルな実装になりました。

こちらを使いませんでした

これらは使いませんでした

  1. jQuery の利用
  2. sitemap.xml の利用( $.ajax(...) で自ブログに再アクセスする仕組み)
  3. FontAwesome の利用
  4. 既存の「はてなブログ 更新日」でググってヒットする記事

上記の 1. と 2. と 3. は私の好みではなかったから避けました。(理由は「方針」の項にて。)

既存の記事(4. です)はこの3つに抵触しているものがほとんどだったので使えなかったです。なので、 1. と 2. と 3. が問題なしと思う人なら既存の記事で全然OKだと思います。「はてなブログ 更新日」でググってヒットする記事がたくさんありますので、その中からお好きなものを使っても良いでしょう。(抵触してなかったけどテンプレートの違いなのか上手く動かないものもあったなー。)

逆に、これらを使いました

  1. JavaScript の標準関数の利用【脱jQuery】【脱外部ライブラリ】
  2. JSON-LDの利用【脱sitemap.xml利用】
  3. はてなブログ搭載済みのアイコンの利用【脱FontAwesome】【脱外部ライブラリ】
  4. 追加する更新日は <span> タグにする(非 <time> タグ)

コッチの方がいいじゃんという方は、当記事が参考になれば幸いです。尚、なぜこうしたかのお話は「方針」の項に任せます。

変更内容

記事ヘッダーに更新日も表示されるようになりました。ついでに、作成日のデザインも変更しています。

記事ヘッダーに更新日も表示
記事ヘッダーに更新日も表示

仕様

以下のような仕様になっています。

  • 「更新日」は、「作成日」の右隣に表示します。
  • 【変更可】「更新日」は、「作成日」と日付が異なる場合のみ表示します。
  • 日付はハイフンつなぎの yyyy-MM-dd 形式にしています。
  • 【変更可】日付の前にアイコンを、後ろに「作成」or「更新」という文言を付けています。
  • 【変更可】追加する「更新日」は <span> タグです。
  • 「作成日」のリンクはそのまま残し、「更新日」にリンクは付けません。

ここで【変更可】と書いている項目は、「変更方法」の項の中で対処方法を書いています

ちなみに、『「更新日」は、「作成日」と日付が異なる場合のみ表示』としている理由は、カテゴリーの設定ミスやタグの付け忘れなど、ちょっとしたミスで更新することが結構あるからです。その場合は「更新してないよ」って体裁にするという考えです。この点も【変更可】ですので、一律表示したい方は以下の文章を読んで対応してください。

変更方法

HTML, JavaScript の変更手順

管理画面から以下のようにたどります。

デザイン > レンチマーク > サイドバー > ヘッダ

ここに次項にある「追加 HTML, JavaScript」の内容を追記します。

追加 HTML, JavaScript

<!-- 記事ヘッダーの作成日・更新日 -->
<script>
  document.addEventListener('DOMContentLoaded', function () {
    // 各要素を取得
    const jsonld = JSON.parse(
      document.querySelectorAll('head script[type="application/ld+json"]')[0]
        .innerText
    ); // JSON-LD
    const datePublished = jsonld.datePublished; // 作成日文字列
    const dateModified = jsonld.dateModified; // 更新日文字列
    const entryDate = document.querySelector('header.entry-header .entry-date'); // 日付表示領域

    // 取得できなかったら処理終了
    if (!jsonld) return;
    if (!datePublished) return;
    if (!dateModified) return;
    if (!entryDate) return;

    // 「更新日要素」を作成
    const modifiedElm = document.createElement('span'); // !!!注意 1!!! 
    modifiedElm.innerText = dateModified.substr(0, 10);
    modifiedElm.className = 'modified-date';

    // 日付が違った場合は「更新日要素」を追加
    if (datePublished.substr(0, 10) !== dateModified.substr(0, 10)) { // !!!注意 2!!!
      entryDate.appendChild(modifiedElm);
    } // !!!注意 2!!!
  });
</script>

このスクリプトを利用される場合の注意事項です。

  1. 「更新日」を span タグで追加しています。任意のタグ( time とか)に変更してもOKです。 CSS にも影響はありません。(ただし、インライン要素にしてください。)
  2. 「作成日」と「更新日」が同日だった場合は「更新日」を表示しないようにしています。「更新日」を必ず表示させたい場合は「!!!注意 2!!!」が書かれている if(...) {} の行を削除してください。

CSS の変更手順

管理画面から以下のようにたどります。

デザイン > レンチマーク > デザインCSS

ここに追記をします。

追加CSS

/* 記事ヘッダーの作成日・更新日 */
.entry-header .entry-date {
  color: #6f8383; /* !!!注意 1!!! */
}
.entry-header .entry-date a time {
  font-size: 0;
}
.entry-header .entry-date a time > span {
  font-size: .9rem;
}
.entry-header .entry-date a time::before { /* !!!注意 2!!! */
  font-family: blogicon;
  content: "\f03a"; /* blogicon-calendar */
  font-size: .9rem;
  margin-right: 3px;
}
.entry-header .entry-date a time::after { /* !!!注意 3!!! */
  content: "作成";
  font-size: .9rem;
  margin-left: 3px;
}
.entry-header .entry-date .modified-date {
  font-size: .9rem;
  margin-left: 10px;
}
.entry-header .entry-date .modified-date::before { /* !!!注意 2!!! */
  font-family: blogicon;
  content: "\f02b"; /* blogicon-repeat */
  font-size: .9rem;
  margin-right: 3px;
}
.entry-header .entry-date .modified-date::after { /* !!!注意 3!!! */
  content: "更新";
  font-size: .9rem;
  margin-left: 3px;
}

この設定を利用される場合の注意事項です。

  1. 文字色です。任意の色に設定してください。
  2. 先頭にアイコンを追加する設定です。不要な場合はこのブロックを丸ごと削除してください。
  3. お尻に「作成」と「更新」という文字を追加する設定です。不要な場合はこのブロックを丸ごと削除してください。

説明(開発者向け)

今回の対応方針と、追加した JavaScript と CSS の実装内容の説明です。利用するだけの人は読まなくても大丈夫です。

方針

先にも書きましたが、以下の方針で作成しました。

  1. JavaScript の標準関数の利用【脱jQuery】【脱外部ライブラリ】
  2. JSON-LDの利用【脱sitemap.xml利用】
  3. はてなブログ搭載済みのアイコンの利用【脱FontAwesome】【脱外部ライブラリ】
  4. 追加する更新日は <span> タグにする(非 <time> タグ)

以下に説明を続けます。

脱jQuery、脱FontAwesome

  • jQuery , FontAwesome を読み込むこと
  • jQuery に依存すること

が嫌だったので使わない方法にしました。

jQuery は偉大でしたが、まあ使わなくなりつつあるのは時流でしょうしね。

FontAwesome は全然使っていいと思ってますが、外部ファイルを読み込むのが嫌だったのでやめました。はてなブログには既に搭載済みのオリジナルアイコンがありましたので、こちらを利用することにしました。

kamasanchi.hatenablog.com

上記の記事に利用可能なアイコンがまとまっていました。ありがたく利用させていただきました。

JSON-LD

JSON-LD って何でしょ?

はてなブログの HTML 内にはこういうタグが含まれています。コイツです。

<script type="application/ld+json">
  {
    "@context": "http://schema.org",
    "@type": "Article",
    "dateModified": "2021-01-27T05:26:39+09:00",
    "datePublished": "2015-12-29T19:22:48+09:00",
    "headline": "はてなブログで目次を表示するようにしました",
    "image": [
      "https://cdn-ak.f.st-hatena.com/images/fotolife/h/hiranoon/20210115/20210115013559.png"
    ]
  }
</script>

こいつは何なのかって説明は Google さんの説明に任せましょう。以下に引用します。(引用は「構造化データ ≒ JSON-LD」として読むと理解しやすい。)

developers.google.com

ページに構造化データを含めて、ページの内容についての明白な判断材料を提供すると、Google でそのページをより正確に理解できるようになります。 構造化データとは、ページに関する情報を提供し、ページ コンテンツ(中略)を分類するために使用される、標準化されたデータ形式です。

要は、 Google や Twitter など向けに、記事の情報を調べるのが楽になるようブログ側が提供してあげるデータということです。その標準規格が JSON-LD です。

この JSON-LD は既にはてなブログに含まれているので、こいつを利用すれば楽なんじゃないかと思った訳です。 sitemap.xml に再アクセスしたりなんて不要でしょう。

time タグ不使用の理由

これは前2項と違い、非常に弱い理由になります。以下は単なる使わない言い訳なので飛ばしてOKです。。。(一応書き残しておきます。)

実は、「作成日」には <time> タグが使われています。じゃあ「更新日」も <time> タグでいいじゃん、なんですけど、あえて <span> にしました。

MDN の <time> タグの説明を見てみましょう。

developer.mozilla.org

(前略)datetime 属性を使用して、機械可読な形式の日付を記述することができ、検索エンジンの結果を改善したりリマインダーなどの独自機能に使用したりすることができます。

「更新日」って JavaScript でムリヤリ後付けしている文字情報ですし、検索エンジン関係ない気がします。やるならちゃんとタグを作り込むべきでしょうが、それは面倒だしメンテも手間というのがあって、、、あえて「意味のない」飾りとして振る舞うべく <span> にしました。

まあ、横着ですね。 <time> タグでもいいと思います。本当はセマンティックに <time> タグにするべきなのかも知れませんね。

JavaScript の実装

ここから実装内容の説明になります。

JavaScript では「更新日」の HTML を追加するロジックが組まれています。

起動条件

document.addEventListener('DOMContentLoaded', function () { ... }); で、画面描画時に起動するようになっています。良くある処理ですね。この中に HTML を後付けで編集する処理が書かれています。

JSON-LD の取得

JSON-LD の取得方法は(自分でコードを考えるのが面倒だったのでググって、、、)こちらを利用しました。

manjiro.net

querySelectorAll で取ってきて JSON.parse(...) するだけ。ワンライナーだし良き。シンプル・イズ・ベスト! 尚、今回はセレクタに head を加える変更を行っています。

    const jsonld = JSON.parse(
      // セレクタの先頭に「head 」を追加しています。 
      document.querySelectorAll('head script[type="application/ld+json"]')[0]
        .innerText
    );
    const datePublished = jsonld.datePublished;
    const dateModified = jsonld.dateModified;

HTML から <script type="application/ld+json"> を取得して利用します。

どうもはてなブログでは「パンくず」でも <script type="application/ld+json"> が使われているようです。セレクタに <head> 配下という指定を追加したのはこういう事情があります。

取得した JSON-LD から作成日時と更新日時を抽出しています。ちなみに、取得した日付文字列は 2021-01-27T05:26:39+09:00 のような形式になっています。

「更新日要素」を作成

「更新日」を <span> タグとして作成しています。前述の通り、このタグは <time> にしてもOK。

    // 「更新日要素」を作成
    const modifiedElm = document.createElement('span'); 
    modifiedElm.innerText = dateModified.substr(0, 10); // 先頭10文字で年月日を取得
    modifiedElm.className = 'modified-date'; // CSS のために class を付けておく

同日でなければ日付表示領域に「更新日要素」を追加

「作成日文字列」の年月日と、「更新日文字列」の年月日が合致した場合は表示させない仕様にしています。

同日でなかったなら、日付を表示する領域の中に「更新日要素」を追加します。

    const entryDate = document.querySelector('header.entry-header .entry-date'); // 日付表示領域

    // ...

    // 日付が違った場合は「更新日要素」を追加
    if (datePublished.substr(0, 10) !== dateModified.substr(0, 10)) {
      entryDate.appendChild(modifiedElm); // ちょうど作成日の後ろに入ります。
    }

出力結果

ということで、上記スクリプトにより、以下のような HTML が生成されます。

<div class="date entry-date first">
  <a href="https://multimineral-tech.com/archive/2021/02/05" rel="nofollow">
    <time datetime="2021-02-04T16:23:37Z" title="2021-02-04T16:23:37Z">
      <span class="date-year">2021</span><span class="hyphen">-</span
      ><span class="date-month">02</span><span class="hyphen">-</span
      ><span class="date-day">05</span>
    </time>
  </a>
  <span class="modified-date">2021-02-05</span><!-- 追加される!!! -->
</div>

以下のように表示されます。

JavaScript による HTML の変更結果
JavaScript による HTML の変更結果

こういう HTML になることを前提として、コイツを装飾していきます。

CSS の実装

疑似要素で前にアイコン、後ろに文言を追加

CSS の疑似要素 ::before::after で、アイコンと文言をそれぞれ追加します。

/* 作成日の前 */
.entry-header .entry-date a time::before {
  font-family: blogicon;
  content: "\f03a"; /* blogicon-calendar */
}
/* 作成日の後 */
.entry-header .entry-date a time::after {
  content: "作成";
}
/* 更新日の前 */
.entry-header .entry-date .modified-date::before {
  font-family: blogicon;
  content: "\f02b"; /* blogicon-repeat */
}
/* 更新日の後 */
.entry-header .entry-date .modified-date::after {
  content: "更新";
}

はてなブログのアイコンはコードを指定して使います。先にも書きましたが、利用方法は下記の記事を参考にしています。

kamasanchi.hatenablog.com

これらにより、以下のような表示が、

JavaScript による HTML の変更結果
JavaScript による HTML の変更結果

以下のように変わりました。

CSS でアイコンと文言を追加
CSS でアイコンと文言を追加

謎のスペースの除去

さて、「作成日」だけ謎のスペースが存在することに気が付きましたか? カレンダーアイコンと日付文字列の間です。分かりますか?

謎のスペースが発生
謎のスペースが発生

HTML 中の改行やスペースが出力されてしまっているのが原因です。

HTML 中の改行やスペースが出力されてしまっている
HTML 中の改行やスペースが出力されてしまっている

「更新日」は HTML 中に無駄な改行やスペースがないので、謎のスペースが現れません。

「作成日」と「更新日」でズレがあると装飾がしにくいです。ですので、この謎のスペースを取り除いてから装飾を行います。今回は、一旦 font-size: 0; にして謎のスペースを非表示にする TIPS を利用します。

この TIPS の詳しい内容は以下の記事を参照ください。

multimineral-tech.com

その TIPS を追加した CSS が以下です。文字サイズを 0 にして非表示にしてから、「作成日」と「更新日」とそれぞれの前後のアイコン&文言の計6ヶ所の font-size を上書き指定しています。

.entry-header .entry-date a time {
  font-size: 0; /* スペースもろとも配下の文字を消してしまう */
}
.entry-header .entry-date a time > span {
  font-size: .9rem; /* 表示したいのでサイズを上書き */
}
.entry-header .entry-date a time::before {
  font-family: blogicon;
  content: "\f03a";
  font-size: .9rem; /* 表示したいのでサイズを上書き */
}
.entry-header .entry-date a time::after {
  content: "作成";
  font-size: .9rem; /* 表示したいのでサイズを上書き */
}
.entry-header .entry-date .modified-date {
  font-size: .9rem; /* 表示したいのでサイズを上書き */
}
.entry-header .entry-date .modified-date::before {
  font-family: blogicon;
  content: "\f02b";
  font-size: .9rem; /* 表示したいのでサイズを上書き */
}
.entry-header .entry-date .modified-date::after {
  content: "更新";
  font-size: .9rem; /* 表示したいのでサイズを上書き */
}

これらにより、以下のような表示が、

CSS でアイコンと文言を追加
CSS でアイコンと文言を追加

以下のように変わりました。

CSS で謎のスペースを除去
CSS で謎のスペースを除去

地味ですが、謎のスペースが取り除かれ、「作成日」と「更新日」が(文字色以外は)同じ表示となりました。

余白と文字色の調整

ここまで来たらあとは簡単。文字色と余白を調整するだけです。以下のコード中のコメント部分を追加しました。

.entry-header .entry-date {
  color: #6f8383; /* 色変更 */
}
.entry-header .entry-date a time {
  font-size: 0;
}
.entry-header .entry-date a time > span {
  font-size: .9rem;
}
.entry-header .entry-date a time::before {
  font-family: blogicon;
  content: "\f03a";
  font-size: .9rem;
  margin-right: 3px; /* 余白追加 */
}
.entry-header .entry-date a time::after {
  content: "作成";
  font-size: .9rem;
  margin-left: 3px; /* 余白追加 */
}
.entry-header .entry-date .modified-date {
  font-size: .9rem;
  margin-left: 10px; /* 余白追加 */
}
.entry-header .entry-date .modified-date::before {
  font-family: blogicon;
  content: "\f02b";
  font-size: .9rem;
  margin-right: 3px; /* 余白追加 */
}
.entry-header .entry-date .modified-date::after {
  content: "更新";
  font-size: .9rem;
  margin-left: 3px; /* 余白追加 */
}

これらにより、以下のような表示が、

CSS で謎のスペースを除去
CSS で謎のスペースを除去

以下のように変わりました。

CSS で文字色と余白を調整
CSS で文字色と余白を調整

めでてぇ。

あとがき

なんやかんやでオジリナルな実装を書いてみました。 JavaScript と CSS 、思ったより長くない実装になりました。

多分、はてなブログであれば動くと思います。あと、スマートフォン用の対応は別途必要になるかも知れません。レスポンシブにしていればこの記事の内容のみで行けると思います。

multimineral-tech.com

ということで、当記事が参考になったなら幸いでございます。