制作記事 Web制作アプリケーションWordPressコメントされたときのみ、コメント最新リストを更新する

コメントされたときのみ、コメント最新リストを更新する

最新コメント5件を表示するような共通エリアを、すべてのページに用意するお話しです。

実現したいこと

最新コメント5件を表示するような共通エリアを用意する際の要件をまとめました。

  • ある記事に複数のコメントがある場合はユニークとして最新のコメントのみカウントとし、記事が重複しないようにする
  • ページをアクセスするたびにデータベースを参照するのではなく、コメントされたときにスタティックなファイルを事前に生成しておき、それを参照する
  • 対象のコメントは、公開されている・許可されているコメントのみで、保留やスパム判定されたコメントやPINGは対象外とする

実装までの思考

WordPressのテンプレートには、コメントを軸としたテンプレートはないので、別途、固定ページなどで専用ページを用意する必要がある。とりあえず、page-comments.php を用意して、コメント一覧を表示するページを作ろう。

このままだと、ページにアクセスするたびに、page-comments.phpを呼び出す、つまり都度データベースを参照してしまうのでよろしくない。とはいえ、サーバーキャッシュ対応はレンタルサーバーだとできないので、別案を考える。

コメントされたタイミングで、スタティックファイルを作る。ページにアクセスするたびに、そのスタティックファイルを参照するようにする。

つまりは、重要なポイントは2つ。
それは「コメント一覧を表示する」ことと「コメントがあったタイミングをフックにする」ことだ。
それではそれぞれ実装していきます。

下準備

実装するためのテスト用ファイルを用意します。
WordPressが有効になる必要があります。どのテンプレートファイルでも対応しますので、トップページなり、固定ページなり、投稿ページなり、エラーページなり、お好きなように。

コメント一覧を表示する → get_comments

コメント情報を取得するには、関数 get_comments を利用します。
引数には多くの条件を指定できるので、大概のことはこの関数で絞り込みや並び替えを行うことができるでしょう。
詳しくは、公式リファレンスを参照します。
関数リファレンス/get comments – WordPress Codex 日本語版

今回は、取得対象を「公開許可しているコメント」として情報を取得します。とりあえず、コメント本文を出力する例です。

$args_comment = array(
  'type' => 'comment',
  'status' => 'approve',
);
foreach ($comments as $comment) {
  echo $comment -> comment_content;
}

これだけで、サイト内のすべての許可したコメントの本文のみが表示されます。
htmlやCSSの反映はここでは省きますが、よしなに。
ちなみに、本文以外にもコメントごとに下記のような情報が返却されています。

戻り値

comment_ID (整数) コメントの ID
comment_post_ID (整数) コメントが付いた投稿または固定ページの ID
comment_author (文字列) コメント投稿者の名前
comment_author_email (文字列) コメント投稿者のメールアドレス
comment_author_url (文字列) コメント投稿者のウェブサイト
comment_author_IP (文字列) コメント投稿者の IP アドレス
comment_date (文字列) コメントの日時 (YYYY-MM-DD HH:MM:SS)
comment_date_gmt (文字列) コメントの GMT 日時 (YYYY-MM-DD HH:MM:SS)
comment_content (文字列) コメント内容
comment_karma (整数) コメントのカルマ値 (訳注: 常に0です)
comment_approved (文字列) コメントの承認レベル (0, 1 または "spam")
comment_agent (文字列) コメント投稿者のユーザーエージェント (ブラウザーやオペレーティングシステムなど)
comment_type (文字列) 該当すればコメントの種類 (pingback|trackback), 普通のコメントなら空
comment_parent (文字列) 入れ子になったコメントなら親コメントの ID (トップレベルなら0)
user_id (整数) コメント投稿者が登録済みならユーザー ID (未登録なら0)

コメントありの記事を5件取得するためにカスタマイズする

$comment_maxnum = 5;    // 5件取得する
$comment_num = 0;    // 記事数をカウントする
$comment_array = array();    // 記事IDを格納する
$args_comment = array(
  'type' => 'comment',
  'status' => 'approve',
);
$comments = get_comments($args_comment);
foreach ($comments as $comment) {
  $post_id = $comment -> comment_post_ID;    // 記事IDを取得する
  // 記事IDが重複していないか判別する
  if (in_array($post_id, $comment_array)) {
    // 重複しているため、次のコメントあり記事を参照する
    continue;
  // 記事数が所得したい件数より少ないか判別する
  } else if ($comment_num < $comment_maxnum) {
    $comment_num++;    // 取得記事数を追加する
    $comment_array[] = $post_id;    // 記事IDを格納する
    echo $comment -> comment_content;
  } else {
    // 取得したい件数に達したので、このループから抜ける
    break;
  }
}

これで、一つ目の「コメント一覧を表示する」は実装完了。この記述をすべてのテンプレートに適用させてもいいのだが、このままだとサイト内の各ページにアクセスするたびにデータベースを参照するので、コメントがあったときにファイルを更新して、スタティックファイルを用意する。

コメントがあったタイミングをフックにする → wp_insert_comment

公式サイトを漁っていたら、コメントがあったタイミングをフックにする関数を見つけたので、これをfunctions.php に適用するのみ。
【注意】functions.php を修正する場合は、必ずファイルをバックアップしてから修正することを強くオススメします。コードに誤りがあるとサイトが閲覧できなくなる可能性があるので、扱い要注意です。

function mp_comment_inserted($comment_id, $comment_object) {
    // do something
}
add_action('wp_insert_comment', 'mp_comment_inserted', 99, 2);

これで、コメントがあったタイミングをフックにする処理ができます。関数名「mp_comment_inserted」は任意です。ご自身の命名ルールで。
do something の箇所に、さきほどテストしたコードをこちらに差し替え、echoではなく、file_put_contentsでファイルを作成するようにすれば完成です。

function mp_comment_inserted($comment_id, $comment_object) {
  $comment_maxnum = 5;
  $comment_num = 0;
  $comment_array = array();
  $comment_text = '';    // 保存用テキスト
  $args_comment = array(
    'type' => 'comment',
    'status' => 'approve',
  );
  $comments = get_comments($args_comment);
  foreach ($comments as $comment) {
    $post_id = $comment -> comment_post_ID;
    // 記事IDが重複していないか判別する
    if (in_array($post_id, $comment_array)) {
      continue;
    } else if ($comment_num < $comment_maxnum) {
      $comment_num++;
      $comment_array[] = $post_id;
      $comment_text .= $comment -> comment_content;    // テキストを追加する
    } else {
      break;
    }
  }
  // テキストを保存する
  file_put_contents(__DIR__.'/include_comment.html', $comment_text);
}
add_action('wp_insert_comment', 'mp_comment_inserted', 99, 2);

include_comment.html というファイルを生成 or 上書きするように指定していますが、もちろんファイル名や階層もよしなに変更で。
ちなみに、functions.php 内に移動した場合は、先に用意したテスト用のテンプレートは不要となり、include_comment.html をincludeするようにします。

最後に

この記事で紹介した内容で、このブログの全ページに「最近の記事」「人気の記事」がありますが、ここに「コメントありの記事」というエリアを追加しました。