読者です 読者をやめる 読者になる 読者になる

Corredor

ウェブ、プログラミングの勉強メモ。

はてなブログでページの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>

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

  • やっていることとしては、フッタにある AdSense 広告を囲んだ div 要素を複製し、オリジナルの div 要素を削除したら、「1記事」を示すクラス群の最初の要素の末尾に複製した要素を追加している。
  • はてなブログはページごとにテンプレート HTML が異なるので、body 要素に振られているクラスから、「1記事」を示すクラス名を特定する必要がある。hasClass() はコレを判定している。
  • 今回は「トップページと記事ページ」、「アーカイブページ」の2種類のみ対応し、閲覧される頻度が少ない「About」ページなどは対応しないようにした。対応していないページでは、AdSense 広告はフッタ領域に表示されるので、デザイン上の都合からフッタには表示したくない、などの場合は別途対応する。

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

  • hasClass() の判定は、indexOf() !== -1~ で代替した方が短くなる。
  • 即時関数に引数を渡せることを利用して、document と半角スペース " " を事前に変数化しておく。この渡し方だと、スコープ内で var d = document, s = " "; と書いた時と較べて、イコール = の分だけ短縮できる。

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

以上!

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

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

neos21.hatenablog.com

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

Google AdSense 成功の法則 57

Google AdSense 成功の法則 57