【wordpress】コメントの入力欄を追加する/wp_list_comments表示カスタマイズ

2015.3.16 Wordpress

wordpressでコメント入力欄を追加する→表示まで

wordpressで口コミサイト、アフィリエイトサイト、掲示板機能を実装するにあたって必須なのがこの「コメント機能」。

検索するといくつかの方法が出てくるのですが、コメント欄が追加されなかったり、コメント欄だけ追加されて、データベースには格納されないものだったり…

なんだか上手く実装できないのが多かったのですが、僕の場合で上手く言った事例を各フェーズの備忘録としてメモしていきます。

wordpressコメント項目の追加にあたって、今回のケース

なんだか面倒になりそうなので、先にサクっとシチュエーションを決めましょう。

今回は、「口コミ」機能の実装を目指して、wordpressコメント機能に

  • 「タイトル」
  • 「性別」
  • 「年齢」

を選択する項目をつけることにします。

「性別」「年齢」は複数選ばれる必要が無いしあってはいけないので、ラジオボタンで選択するようにします。

<input type="radio" name="ボタングループの識別名(重複防止)" value="選択値1">
<input type="radio" name="ボタングループの識別名(重複防止)" value="選択値2">
<input type="radio" name="ボタングループの識別名(重複防止)" value="選択値3">

「タイトル」は、テキストボックスですね。

<input type="text" name="commentTitle" value="" placeholder="この商品についてひとこと" />

どちらも、nameをキーとしたvalue値(選択/入力)が渡されます

そして投稿などのページでwp_list_comments関数が呼び出される時に表示されることになります。
wp_list_comments:WordPress私的マニュアル

ちなみにwordpressバージョンは、WordPress 4.1.1で実装しました。
だいたいその前のバージョンでも出来ると思いますがあまりにも古いと動作の保証はありません。また、いかなるトラブルも一切の責任を負いかねます。

1.コメント項目の追加

function.phpに以下のコードを追記。

add_filter( 'comment_form_defaults','change_comment_form_input');
function change_comment_form_input($default) {
   
     ///////入力項目のカスタマイズ(名前のあとにつづく)

     ////タイトル
     $default['fields']['email'] .= '<p class="comment-form-author commentForm-title">
     <label for="commentTitle">'. __('タイトル') . '</label>
     <input type="text" name="commentTitle" value="" placeholder="この商品についてひとこと" />
     </p>';

     ////性別
     $default['fields']['email'] .= '<p class="comment-form-author">
     <label for="imMan"><input type="radio" name="sex" value="男性" id="imMan" />'. __('男性') . '</label>
     <label for="imWoman"><input type="radio" name="sex" value="女性" id="imWoman" />'. __('女性') . '</label>
     </p>';

     ////年齢層
     $default['fields']['email'] .= '<p class="commentForm-age">
     <label for="teen"><input type="radio" name="commenterAge" value="10代" id="teen" />'. __('10代') . '</label>
     <label for="teen2"><input type="radio" name="commenterAge" value="20代" id="teen2" />'. __('20代') . '</label>
     <label for="teen3"><input type="radio" name="commenterAge" value="30代" id="teen3" />'. __('30代') . '</label>
     <label for="teen4"><input type="radio" name="commenterAge" value="40代" id="teen4" />'. __('40代') . '</label>
     <label for="teen5"><input type="radio" name="commenterAge" value="50代" id="teen5" />'. __('50代') . '</label>
     </p>';

     return $default;
}

直接HTMLコードを代入しています。

なにをやっているか

自作の関数change_comment_form_inputを、wordpressの機能「フィルターフック」を利用して発動させています。
「フィルターフック」というのは要するに、「wordpressの関数が実行される途中のある決められたポイント(自分で設定もできる)で自作の関数も一緒に実行できる」もので「フィルターフック」「アクションフック」の二種に分かれます。

動作や理解についてはこちらがとても参考になりました。
apply_filters と add_filter の使用方法。 | WEBデザイン&WEBプログラミング -sei2の日記-
関数add_filterについてもこちらを見てみてくださいね!

今回コメントの項目を増やすにあたっては、コメントフォームが表示されるタイミングのフックを利用して関数を発動することで、自作の項目が紛れ込んで画面に表示されるようになるということになります。

add_filter( ‘comment_form_defaults’,’change_comment_form_input’);

add_filterは、既存のフィルターフック(apply_filters関数で設定したもの)にて自作の関数を実行させる命令をする役割を持ちます。
第一引数に「既存のフック名」、第二引数に「実行する関数名」、第三引数に「実行する関数の優先順位」、第四引数に「渡す変数がいくつあるか」を入力します。後者2つは省略するとそれぞれ、「10」「1」になります。
add_filter:WordPress私的マニュアル

なので今回の例だと、フィルターフック「comment_form_defaults」で自作の関数「change_comment_form_input」を実行させる、ということですね。

フィルターフック「comment_form_defaults」は、コメントフォームを出力するもので、
wp-includes\comment-template.phpの2099行目ぐらいに書いてあります。

少し上に読んでいくとwordpress関数であるget_comment関数が実行されるときに発動するということが解ると思います。

2053行目ぐらいからの

$fields   =  array(
'author' => '<p class="comment-form-author">' . '<label for="author">' . __( 'Name' ) . ( $req ? ' <span class="required">*</span>' : '' ) . '</label> ' .
           '<input id="author" name="author" type="text" value="' . esc_attr( $commenter['comment_author'] ) . '" size="30"' . $aria_req . ' /></p>',
'email'  => '<p class="comment-form-email"><label for="email">' . __( 'Email' ) . ( $req ? ' <span class="required">*</span>' : '' ) . '</label> ' .
           '<input id="email" name="email" ' . ( $html5 ? 'type="email"' : 'type="text"' ) . ' value="' . esc_attr(  $commenter['comment_author_email'] ) . '" size="30"' . $aria_req . ' /></p>',
'url'    => '<p class="comment-form-url"><label for="url">' . __( 'Website' ) . '</label> ' .
           '<input id="url" name="url" ' . ( $html5 ? 'type="url"' : 'type="text"' ) . ' value="' . esc_attr( $commenter['comment_author_url'] ) . '" size="30" /></p>',
);

が、2073行目で

$defaults = array(
'fields'               => $fields,
'comment_field'        => '<p class="comment-form-comment"><label for="comment">' . _x( 'Comment', 'noun' ) . '</label> <textarea id="comment" name="comment" cols="45" rows="8" aria-required="true"></textarea></p>',
/** This filter is documented in wp-includes/link-template.php */
'must_log_in'          => '<p class="must-log-in">' . sprintf( __( 'You must be <a href="%s">logged in</a> to post a comment.' ), wp_login_url( apply_filters( 'the_permalink', get_permalink( $post_id ) ) ) ) . '</p>',
/** This filter is documented in wp-includes/link-template.php */
'logged_in_as'         => '<p class="logged-in-as">' . sprintf( __( 'Logged in as <a href="%1$s">%2$s</a>. <a href="%3$s" title="Log out of this account">Log out?</a>' ), get_edit_user_link(), $user_identity, wp_logout_url( apply_filters( 'the_permalink', get_permalink( $post_id ) ) ) ) . '</p>',
'comment_notes_before' => '<p class="comment-notes">' . __( 'Your email address will not be published.' ) . ( $req ? $required_text : '' ) . '</p>',
'comment_notes_after'  => '<p class="form-allowed-tags">' . sprintf( __( 'You may use these <abbr title="HyperText Markup Language">HTML</abbr> tags and attributes: %s' ), ' <code>' . allowed_tags() . '</code>' ) . '</p>',
'id_form'              => 'commentform',
'id_submit'            => 'submit',
'title_reply'          => __( 'Leave a Reply' ),
'title_reply_to'       => __( 'Leave a Reply to %s' ),
'cancel_reply_link'    => __( 'Cancel reply' ),
'label_submit'         => __( 'Post Comment' ),
'format'               => 'xhtml',
);

配列$defaultsに代入されていますね。

フィルターフック用関数であるchange_comment_form_inputでは、実行時に引数で$defaultsを受け取ります。
で、その$defaultsのキーである $default[‘fields’][‘email’]つまりメールの入力欄と一緒に配列にぶち込んでreturnしてしまうということです。

なので、場所としてはメールの入力欄のあとにつづけて出る感じになります。

ここまででおそらく以下のようになるかと思います。

index

(テーマはTwentyFifteen)

メール入力欄の後なんて嫌だ!って方は、

 $default['fields']['★ここをauthorかurlに変更★']

2 ちゃんとデータベースに入れる

function.phpに以下のコードを追記。

///////データ更新
////性別
add_action( 'comment_post', 'save_comment_meta_data_sex' );
function save_comment_meta_data_sex( $comment_id ) {
$sex = $_POST['sex'];
return update_comment_meta( $comment_id, 'sex', $sex, true);
}
///タイトル
add_action( 'comment_post', 'save_comment_meta_data_title' );
function save_comment_meta_data_title( $comment_id ) {
$commentTitle = trim($_POST['commentTitle']);
return update_comment_meta( $comment_id, 'commentTitle', $commentTitle, true);
}
////年齢層
add_action( 'comment_post', 'save_comment_meta_data_age' );
function save_comment_meta_data_age( $comment_id ) {
$commenterAge = $_POST['commenterAge'];
return update_comment_meta( $comment_id, 'commenterAge', $commenterAge, true);
}

なにをやっているか

今度はadd_action関数です。
add_filterとできることは同じなのですが、使い分けとしては、codexに以下のように書いてあります。

アクションは、WordPress で発生する特定のイベント、例えば投稿の公開、テーマの変更、管理画面の表示などによって始動させらせます。プラグインは PHP 関数を実行することによってこのイベントに反応することができます。このイベントへの反応には次のようなものがあります:

データベースのデータの変更
メールメッセージの送信
ブラウザ画面(管理画面もしくは読者が閲覧する画面)に表示する項目の変更

フィルターは、実行中の特定のポイント、データに何かのアクション(データベースへの追加やブラウザスクリーンに送り出すなど)を行なう前にデータが通過する関数です。フィルターはデータベースとブラウザの間に位置し(WordPress がページを生成するとき)、ブラウザとデータベースの間にも位置します(WordPress が新しい投稿やコメントをデータベースに追加するとき)。WordPress のほとんど入力と出力は最低ひとつはフィルターを通過します。WordPress はデフォルトでいくつかのフィルタリングを行なっていて、プラグインで追加することができます。

WordPress にフィルタを追加する基本的(詳細はさらに下で説明)な手順は:

データをフィルタリングする関数を作成
add_filter を呼び出して WordPress のフィルタにフック
作成した PHP 関数をプラグインファイルに入れ、有効化

要するにadd_filterが裏方的な処理にフックするのに対し、add_actionはその反対で具現化するほうの処理にフックする感じですね。(誰か上手な説明おねがいいたします)

入力してもらった「タイトル」「性別」「年齢」はpostメソッドで送っているので、それぞれを$_POSTで受け取ります。べつに$_REQUESTでもいいです。
$_REQUESTに入る値と、その優先順位 – [PHP + PHP] ぺんたん info

今回はひとつしか選択できない項目ばかりなのでいいのですが、
チェックボックス機能を付けたりすると、受け取った値をforeachループさせて配列変数に代入してあれこれ~…と面倒なので今回は割愛します。

add_action( ‘comment_post’, ‘~~~’ );

ここでフックする「comment_post」は、コメントがデータベースに保存される直前に実行されるものです。

add_filters関数はapply_filters関数で作られたフックを使うのに対し、add_action関数はdo_action関数でフックを作っています。

このcomment_postがどこで作成されているかというと、wp-includes\comment.phpの1709行目あたりに記載があります。

do_action( 'comment_post', $comment_ID, $commentdata['comment_approved'] );

wp_new_comment関数の中ですね。ここでフックが作られています。

update_comment_meta( $comment_id, ‘commenterAge’, $commenterAge, true);

それぞれをデータベースに記録します。厳密にはそうでなく、「コメントmeta情報の更新」だそうですが、なんだかわかりづらいので便宜上「データベースに記録」といいます。
第一引数には「記録したいコメントのID」第二引数は「キー名(name値)」第三引数に「記録したい値」続いて第四引数は省略していいと思います。特に影響はないように思えました。
update_comment_meta:WordPress私的マニュアル

3 入力してくれた値を表示する

functions.phpに以下のコードを追記します。

////////出力
////性別
add_filter( 'get_comment_author_link', 'attach_sex_to_author' );
function attach_sex_to_author( $author ) {
  $sexies = get_comment_meta( get_comment_ID(), 'sex');
  if ( $sexies ) {
          foreach ($sexies as $sex)
            $author .= $sex . ' ';
     }
     return $author; //コメント者の後に続けて出力。
}
////年齢層
add_filter( 'get_comment_author_link', 'attach_age_to_author' );
function attach_age_to_author( $author ) {
  $age = get_comment_meta( get_comment_ID(), 'commenterAge');
  if ( $age ) {
       $author .= '(' .$age . ')';
     }
     return $author; //コメント者の後に続けて出力。
}

今回はadd_filterです。

なにをやっているか

使っているwordpressテーマにもよりますが、大体はデフォルトの状態で、記事の下にその記事に対するコメントが連なると思います。

以下で説明しますが、get_comment_author_linkというフックを利用し、値を付け加えることで、ある程度任意の場所に表示することができます。

add_filter( ‘get_comment_author_link’, ‘~~~~’ );

このget_comment_author_linkというフックは、コメントしてくれた人の名前を表示する処理の中のフックで、要するにコメントしたユーザー名の後に「年齢」「性別」を出してしまおう、と言う魂胆です。
これが作成されている場所については/wp-includes/comment-template.phpの201行目ぐらいに記述があります。

function get_comment_author_link( $comment_ID = 0 ) {
$url    = get_comment_author_url( $comment_ID );
$author = get_comment_author( $comment_ID );

if ( empty( $url ) || 'http://' == $url )
$return = $author;
else
$return = "<a href='$url' rel='external nofollow' class='url'>$author</a>";

/**
* Filter the comment author's link for display.
*
* @since 1.5.0
*
* @param string $return The HTML-formatted comment author link.
*                       Empty for an invalid URL.
*/
return apply_filters( 'get_comment_author_link', $return );
}

get_comment_author関数でコメントしたユーザーの名前を取得し$authorに代入しています。
フック用の自作関数ではこの変数を引数に取り、「.=」のかたちで値を追加してreturnします。

get_comments_meta()

コメントの値を返します。
第一引数に「コメントのID」、第二引数に「キー(フォームのname値)」、第三引数には「true(最初で見つかった値のみ取得)もしくはfalse(見つかった値全てを配列で取得)」を指定します。
ここでは一応配列で取得して、ループさせる手段をとりました。

それぞれ、代入した値を$authorに追加してreturnします。
これでget_comment_author_linkフックが含まれた関数では、$authorに、項目が追加された状態で処理が進められることになります!

で、しっかりと入力した値が表示された場合がこちらです。

index2

 

表示されました!

真ん中のものはちょっといろいろ試しているときに性別が上手く取得できていなかったため年齢だけの表記ですが、名前のあとに、選んだものが表示されています。

wordpressコメントに追加した入力項目「タイトル」を表示する

コメントのタイトルも、前項と同じ要領で表示できます。

が、「性別」「年代」のように、名前に続いてコメントのタイトルが表示されても如何なものかとなりますよね。
なので、任意の場所に表示することにします。
今までどおりフィルターフックを利用しますが、今回は自由な場所に表示できるように、自分でフィルターフックを作ることにします。

functions.phpに以下のコードを追記します。

////タイトル
add_filter( 'originalFook', 'attach_commentTitle' , 10 , 1 );
function attach_commentTitle( $comment_text ) {
  $titleArg = get_comment_meta( get_comment_ID(), 'commentTitle', false );
  if($titleArg){
    foreach($titleArg as $title){
      $comment_text .= $title;
    }
  }
  return $comment_text;
}

////////コメント出力カスタム
function originalCommentForm($comment , $args , $depth){
  $GLOBALS['comment'] = $comment ;
?>

   <li <?php comment_class(); ?> id="li-comment-<?php comment_ID(); ?>">
     <article id="comment-<?php comment_ID(); ?>">
      <header>
        <h4 class="comments_head">
          <span class="iconIndex-kuchikomi">
          <?php
            //コメント入力欄のタイトルを出力。フック「ordinalFook」作成。
            $kuchikomiTitle = apply_filters('originalFook' , $commentTitle , 1);
            if($kuchikomiTitle){
              echo $kuchikomiTitle;
            }else{
              echo '「' . get_the_title() . '」に関する口コミ';
            }
          ?>          
          </span>
        </h4>
      </header>
      <div class="comment-author vcard">
        <div class="comments_author">
          <?php printf(__('%s'), get_comment_author_link()) ?>
        </div>
      </div>
      <?php if ($comment->comment_approved == '0') { ?>
         <em><?php _e('Your comment is awaiting moderation.') ?></em>
         <br />
      <?php } ?>
 
      <section>
        <div class="comments_body">
          <?php comment_text() ?>
        </div>
      </section>
 
      <footer>
        <div class="comments_footer">
          <p class="comment-meta commentmetadata">
            <a href="<?php echo htmlspecialchars( get_comment_link( $comment->comment_ID ) ) ?>">
            <?php printf(__('%1$s at %2$s'), get_comment_date(),  get_comment_time()) ?>
            </a>
            <?php edit_comment_link(__('(Edit)'),'  ','') ?>
          </p>
           
          <p class="reply">
             <?php comment_reply_link(array_merge( $args, array('depth' => $depth, 'max_depth' => $args['max_depth']))) ?>
          </p>
        </div>
      </footer>
     </article>
<?php
   }
////////コメント出力カスタム

wp_list_comments関数を以下のように変更します。

        $commentArg = array(
          'avatar_size'=> 0 ,
          'callback' => 'originalCommentForm'
        ); 
        wp_list_comments($commentArg);

なにをやっているか

wp_list_commentsのcallback

wp_list_comments関数はコメントを出力させるものですが、コメントの表示をカスタマイズするために、引数に指定する配列にcallbackというキーが用意されています。(詳しい説明は割愛)
wp_list_comments:WordPress私的マニュアル

ここで指定した関数(例の場合ではoriginalCommentForm関数)は必ずfunctions.phpに書いておきましょう。

フィルターフックを自作する

要点だけに絞って説明します。
「タイトル」の入力値を出すためのフィルターフックを作っている箇所が以下となります。

<h4 class="comments_head">
          <span class="iconIndex-kuchikomi">
          <?php
            //コメント入力欄のタイトルを出力。フック「ordinalFook」作成。
            $kuchikomiTitle = apply_filters('originalFook' , $commentTitle , 1);
            if($kuchikomiTitle){
              echo $kuchikomiTitle;
            }else{
              echo '「' . get_the_title() . '」に関する口コミ';
            }
          ?>          
          </span>
        </h4>

この$kuchikomiTitle変数に代入されているのが、「タイトル」入力値です。

apply_filters関数で「originalFook」という名前のフックを作ります。
フックで関数が実行されていて値が返されていれば(=入力値があれば)echoで表示。もし無ければコメントがついたページのタイトルが出力される条件分岐です。

add_filter( ‘originalFook’, ‘~~~’);

自作の「originalFook」フックでattach_commentTitle関数を実行します。

attach_commentTitle関数は今までの項目と同じでget_comment_metaでキーの値から入力値を参照して、それを変数に代入してreturnする処理です。

便宜上、引数の$comment_textに「.=」で値を追加する手段を取っていますが、ここの場合はそうでなくて普通に変数に入れてreturnしても大丈夫だと思います!

おまけ wordpressフォームの項目を削除する

画面キャプチャを見てみると、「webサイト」「メール」の入力欄が無いですね。

これらもfuncitons.phpに以下のコードを記載することで実装できます。

///////コメント欄カスタマイズ
function my_commentForm($fields){
  unset($fields['email']);
  unset($fields['url']);
  unset($fields['comment_notes_before']);
  return $fields;
}
add_filter('comment_form_default_fields' , 'my_commentForm');
add_filter( 'get_comment_time', '__return_false', 10, 2);  // 時間を非表示

さいごに

繰り返しになりますが、wp_list_comments関数の実行で入力値が表示されます。
動作のトラブルなどに関しては一切責任を負いかねます。かならずバックアップをとって作業してください。

別の項目を入力させたい場合は適宜に応じてname値やwp_list_comments関数のcallbackなどを変えてみてください。

でわ!!

Profile

東京でWebデザイナー・コーダーとして、フロントエンド的なことからデザイン思考的なことを考えたりして、ごにょごにょと活動中。(ポートフォリオ)Webクリエイターでは珍しい(?) HIPHOP, R&B好き。休日はよくカフェや漫画喫茶に出向いたりパン屋に行ったりコーヒ豆買いに行ったり、主に散歩しています。。デザインのトレンドやデザイン思考、HTML、CSSからSASS、Javascript、Wordpress構築などコーディングのTIPSなどをブログにアップしていきます。その他のことはtwitter( @satohmsys )まで。コーヒー友達募集中。