SQLiteでもWordPress Cocoonテーマのアクセス集計を使ってみる

この記事は約8分で読めます。

Mediapartners-Google」の記事を書いてしばらくしてから、なぜか突然目に見えてアクセスが減った。
ちょっと前までGoogleで「Nouno」と検索すれば上位に表示されていたのだが、今では何処にも見当たらない。他の記事も軒並み順位を落としているようである。
もしかしたら触れてはいけない事を書いてしまったのかも知れない。。。

Apacheのログを見ていて、そういえばWordPressのCocoonテーマにはアクセス集計機能があったことを思い出した。
当初エラー対策のために互換テーブルを作成して、動くことだけを確認して満足していた。
古の時代、アクセスカウンターなるものが流行した。このアクセスカウンターだが主にPerlで作成されていて、どんなに頑張っても当時は、これがまぁ良くファイルが消失したものである。
そのトラウマがあって、アクセス過多だと標準外のSQLiteだとDBファイルごと消えるのでは?と不安に思い利用を停止していたのだ。

運用を開始して1年経つが、自作のバックアップシステムはトラブル無く完璧に動作している。
夜中にも適度にBotがアクセスしてくるので、wp-cronが想定時間通りにバックアップの指示を出している。日次バックアップを1週間分、週次バックアップを2ヶ月分保持しており、たまにちゃんとバックアップできているか確認するくらいで基本放置だ。
仮にDBファイルが消失しても、前日に戻すのであれば数分で復旧ができる状態である。この辺はSQLiteの強みだろう。

ちょうどアクセスが減ってしまった今がチャンス!
仮にファイルが消失してもなんとかなる!!
ということで、アクセス集計機能をONにしてみた。
何か調整が必要かも?と思っていたら、1年前に作成した互換テーブルは今でも全く問題はなく正常に機能した。Cocoonテーマは比較的更新がまめなのだが、この辺がきっちりされていて大変安心感がある。

1週間程度放置して確認してみると、想定よりアクセス数が多いことに気がついた。Apacheのログと比較してみたのだが、どうやらBotのアクセスログが異常に多い。
/wp-content/themes/cocoon-master/lib/analytics/access.php
へアクセスさせることで、どの記事にアクセスされたか集計しているのだが、クロール時に一緒にアクセスしてしまうようだ。Botのアクセスは、ログに残したくない。

ほとんどのBotは「robots.txt」の言うことを聞くので、対策として以下を追加してみた。

Disallow: /wp-content/themes/

テーマファイルなんかクロールしたところで何も無いので、負荷軽減のためにもテーマファイルごと拒否にしてみた。こうしておけば「access.php」へもアクセスしないはずだ。

数日経つと想定通りにBotからのアクセスログは減ったのだが、某AIエージェントはお構いなしである。しかも頻繁。
このアクセスログを遮断するために「access.php」を解析してみた。
ソースを見ると、WordPress管理者といくつかのBotは最初からアクセスログに残さない仕組みになっていたのだが、メンテが追いつかず最近のBotには対応できていないみたい。某AIエージェントも記載が無かった。

この辺の情報は
/wp-content/themes/cocoon-master/lib/utils.php
の「function is_useragent_robot()」関数に記載があるので確認してみるといいだろう。

「utils.php」をアップデートの度に、某AIエージェントを追加すれば良いのだが、これだと面倒だ。
調べたところ、テーマがカスタマイズされる前提の設計であれば、functions.phpで関数をオーバーライドできることが分かった。ただテーマを作る方は面倒らしい。
Cocoonはこの面倒な仕組みにも対応していた。さすが人気な訳である。

ということで、「functions.php」に以下を追加。これについては通常のMySQLやMariaDBでも動作するはず。

//  lib/utils.phpオーバーライド www.nouno.com
//  ユーザーエージェントがボットかどうか
if ( !function_exists( 'is_useragent_robot' ) ):
function is_useragent_robot(){
  if (!isset($_SERVER['HTTP_USER_AGENT'])) {
    return false;
  }
  $useragents = array(
    'bot',
    'client',
    'crawler',
    'https?://',
    'spider',
    'user',
    'google',
    'meta',
    'MSIE',
    'validator', //各種バリデーター
  );
  $pattern = '{'.implode('|', $useragents).'}i';
  return preg_match($pattern, $_SERVER['HTTP_USER_AGENT']);
}
endif;

元と大幅に違うのだが、preg_match関数を使用して判定していたので、似たようなUSER_AGENTは纏めて拒否して最適化してみた。
大文字小文字も区別しないので「bot」の文字列があれば全て拒否である。
例えば「Googlebot」「bingbot」「amazonbot」なんかが該当する。
人間が使う通常のブラウザには無い文字列だ。これでBotの8割方は拒否できる。
その他にも、ここ1年で集めたUSER_AGENTで、この文字列があったら間違い無くBotというものを追加してみた。もちろん某AIエージェントにも対応しているし、将来的に新しいBotがでてもかなりの確率で拒否できるだろう。
仮に間違っていてもアクセスログだけの影響だ。

それ以外は、ほぼ悪意を持ったBotなので、USER_AGENTが偽装されており単純判断は無理である。唯一の例外が「MSIE」だ。Internet Explorerは既に3年前にサポートを終了しており、Windows11なんか最初からサポート外である。意図的に利用するにはそれなりに知識が必要だし、常用するような人間はまずいない。
ほぼ間違い無くBotだし、人間だとしてもイタズラに近いアクセスなので無視。

一通り設定して、おそらく人間だけだろうというアクセスログを取ることができた。
最近「人気記事」という項目を追加してみたのだが、それに基づくランキングである。自分の認識と一致しており正しいね。
CocoonテーマはSQLiteだと集計ができないという記事を見かけるが、互換テーブルさえ最初に作ってしまえば何も問題なく稼働することが確認できた。

ここまでくると、毎日のアクセス状況を纏めて見てみたい。
もちろんWordPressにログインすれば分かるのだが、自分が欲しい見方と違うのだよね。

ということで、毎日のPV総数とどの記事が読まれたかのリストを表示するスクリプトを作ってみた。
「日付ごとの合計PV数」と「日付、PV数、最終IPアドレス、記事名」を1週間分表示する。
SQLiteって小計のROLLUP句が無いのね?
仕方なく昔ながらの「union all」で結合。

<?php
  header('Content-Type: text/plain; charset=utf-8');
  $db = new SQLite3('[インストール先のディレクトリ]/wp-content/database/.ht.sqlite',SQLITE3_OPEN_READWRITE);
  $result = $db->query("select wp_cocoon_accesses.date,sum(count),'---------------','--------------------' from wp_cocoon_accesses,wp_posts where wp_cocoon_accesses.post_id=wp_posts.ID and wp_cocoon_accesses.date > datetime(CURRENT_TIMESTAMP,'localtime','-8 days') group by wp_cocoon_accesses.date union all select wp_cocoon_accesses.date,sum(count),last_ip,post_title from wp_cocoon_accesses,wp_posts where wp_cocoon_accesses.post_id=wp_posts.ID and wp_cocoon_accesses.date > datetime(CURRENT_TIMESTAMP,'localtime','-8 days') group by wp_cocoon_accesses.date,last_ip,post_date,post_title order by date desc,sum(count) desc");
  while($row = $result->fetchArray()) {
    print($row[0]."\t".$row[1]."\t".$row[2]."\t".$row[3]."\n");
  }
?>

これを自分しか見られないところに設置してみた。
はっきりいうと超手抜き。「text/plain」にしたのは面倒だったのも理由だが、そのまま「TSV」形式で保存できるので、EXCELとかで加工がやりやすいのだ。
完全に自分用だが、CocoonをSQLiteで動かしたときのSQLは見当たらないので、参考までに。

ここまで一通り設定して思った。

Nouno
Nouno

アクセスが半減しているのは、間違い無い。。。

コメント