はてなブログでページの1つ目の記事末尾にだけ AdSense 広告を挿入する JavaScript を作った

はてなブログは各記事の下部に任意の HTML コードを仕込めるが、これはトップページやカテゴリページなどにも有効なエリアなので、ココに Google AdSense 広告のコードを埋め込んでしまうと、記事ごとに AdSense 広告が掲載されるようになってしまう。

2016年夏頃から1ページにおける AdSense の掲載数の上限はなくなったが (それまで1ページ3つまでとされていた)、それでも記事ごとに広告が挟まるのは鬱陶しいし、ページも重たくなる。できれば1つ目の記事の末尾にだけ広告を入れたいものである。

そこで、「記事の下部」ではなく「ページフッター」に広告コードを仕込んでおき、DOMContentLoaded のタイミングでその広告コードを記事の末尾に移動させる、という JavaScript を書くことにした。

フッター HTML の準備

まずはフッターに仕込んでおく HTML の準備。はてなブログの「デザイン」設定画面より「フッタ」セクションに移動し、以下のような HTML コードを埋め込む。

<div id="neos21-adsense-footer" class="neos21-adsense-footer">
  <!-- ココに AdSense の広告コードを仕込む -->
</div>

適当な div 要素で AdSense のコードを囲っておく。id 属性は JavaScript で要素を特定するために使用し、class 属性は CSS での制御に使用する。

AdSense 広告を囲む要素に対して CSS で width 指定をしておけば、レスポンシブ広告のサイズを設定できるし、左右の marginauto にすれば中央揃えにもできるというワケだ。このスタイル指定は、「フッタ」の下の「デザイン CSS」セクションなんかで以下のようにしておくと良いだろう。

.neos21-adsense-footer {
  overflow:hidden;
  margin:20px auto;
  width:300px;
  text-align:center;
}

レクタングル広告が出るように width:300px とした。レスポンシブデザインにしているので、このサイズなら iPhone などで見るときもちょうど良い。overflow:hidden はウィンドウサイズを変更した時に広告が突っ張り棒にならないようにするために書いている。

HTML の準備はコレで OK。

AdSense 広告を移動する JavaScript の設置

次に以下のようなコードを、同じく「フッタ」セクション、先程書いた div 要素の直後にでも書いておく。

(function(d, s) {
  // Body 要素に任意のクラス名が存在するか確認する関数
  var hasClass = function(className) {
    return ~(s + d.body.className + s).replace(/[\n\t]/g, s).indexOf(s + className + s);
  };
  
  // フッタにある AdSense をページ1つ目の記事の最下部に移す関数
  var replaceFooterAdSense = function(articleClassName) {
    var footerAdSense = d.getElementById("neos21-adsense-footer");
    var clone = footerAdSense.cloneNode(true);
    footerAdSense.parentNode.removeChild(footerAdSense);
    d.getElementsByClassName(articleClassName)[0].appendChild(clone);
  };
  
  // Body 要素のクラス名に応じて記事と挿入先のクラス名が異なるので判定する
  d.addEventListener("DOMContentLoaded", function() {
    if(hasClass("page-index") || hasClass("page-entry")) {
      // トップページか記事ページの場合
      replaceFooterAdSense("hentry");
    }
    else if(hasClass("page-archive")) {
      // アーカイブページ (月別・カテゴリ別・検索結果) の場合
      replaceFooterAdSense("archive-entry");
    }
    // About ページなど、これ以外の場合は広告を移動させずそのままフッタに表示する
  }, false);
})(document, " ");

実際は以下のように Uglify (圧縮) したコードを貼ると良い。

<script>
!function(e,n){var t=function(t){return~(n+e.body.className+n).replace(/[\n\t]/g,n).indexOf(n+t+n)},a=function(n){var t=e.getElementById("neos21-adsense-footer"),a=t.cloneNode(!0);t.parentNode.removeChild(t),e.getElementsByClassName(n)[0].appendChild(a)};e.addEventListener("DOMContentLoaded",function(){t("page-index")||t("page-entry")?a("hentry"):t("page-archive")&&a("archive-entry")},!1)}(document," ");
</script>

ポイントは以下のとおり。

Uglify にかけた時に、もう少し短縮化する余地があった部分を予めショートコーディングしておいた。

もっとやろうとするなら、hasClass() 内に "page-" という文字列を事前に仕込んでおけば、hasClass() を使用している引数部分から "page-" という文字列を減らせる。また、replaceFooterAdSense の引数に渡す文字列も、末尾の "entry" 部分は共通なので、その手前の文字列だけを渡すようにしても良い。しかし文字列をちぎってまで短縮すると、今度はひどく難読化するので、今回は避けた。

以上!

さて、この HTML と JavaScript を仕込んでおけば、ページ中の1つめの記事の末尾にだけ、AdSense 広告を載せることが可能になる。

このサイトでは、以前紹介した「シェアリンク」の埋め込みと合わせて先日から導入した。

完全にフッタにあるよりも見てもらえる位置に広告が配置できたので、よきよき。