tips

wordpressのコメント欄をajax化する。

ajaxfy_comment

 

※2018/12/20 …. htmlの表記誤りがあるとき、画像アップロードなど動作が重いときに誤動作を避けられず、現在の環境にそぐわなくなったので使うのをやめました。悪しからず。単純にバリデートに特化したajaxを使用しているので、そのうち紹介するかも。

プラグインに頼らずテーマ内で完結するAJAXコメントフォーム。

前回に引き続き、コメントの周りのカスタマイズ。

一昔前にQuick Commentsというのがあって、いまはAjax CommentsやWP Ajaxify Commentsというのもあって、でも環境依存の問題か上手く動作しなかったり、もっさりしていたりで、いくつもある他のプラグインの動作確認をやるのもしんどいしで、どうにも…あ゛ーって感じになったので、自作してみたら意外とすんなりまとまった、と。

CODE: Ajaxify WordPress comments

<?php
// コメントフォームのAJAX化
function ajaxify_comments_script(){
if ( is_singular() && comments_open() )://固定や投稿等シングルページで動作、場所によっては要変更
?>
<script id="comment-script" type="text/javascript">
jQuery(function( $ ){

    var commentbox_name = '#comments', //コメントテンプレート名、カスタマイズ時は要変更
        commentform_name = '#commentform', //コメントフォーム名、カスタマイズ時は要変更
        commentbox = $( commentbox_name ),
        commentform = $( commentform_name, commentbox );
    ajaxCommentsTrigger();

    function ajaxComments( this_form ){
        var statusdiv = $('<div class="comment-ajax"></div>'); // AJAXの結果を吹き出す窓、デザインはCSSで指定してね
        this_form.append( statusdiv ).submit( function (e) {
            var formdata = this_form.serialize(), // フォームをシリアライズ
                formurl = this_form.attr('action'); // フォームのactionに設定されたurl
            e.preventDefault();
            statusdiv.html('<div class="ajax-processing">コメントを送信中…</div>'); // 送信されると.comment-ajax内に表示
            $.ajax({ 
                type: 'post',
                url: formurl,
                data: formdata
            }).done(function(data,status){
                if( status == "success" ){
                    var matches = data.match(/<body+s+id="error-page">([sS]*?)</body>/);
                    if ( matches ) {
                        var output = $('<div class="ajax-error">' + matches[1] + '</div>');
                        output.find('*:empty').remove();
                        output.find('*:first-child').siblings().remove();
                        statusdiv.html( output );
                        return false;
                    }
                    var newlist = $( data ).find( commentbox_name );
                    if ( newlist.length ){ 
                        statusdiv.html('<div class="ajax-success">コメントありがとうございました。</div>');
                        reply = this_form.parents( 'li.depth-1' ).attr( 'id' );
                        if ( typeof reply !== "undefined" ) {
                            window.location.hash = reply;
                            statusdiv.find( '.ajax-success' ).stop().delay( 500 ).slideUp( 200,function(){
                                commentbox.replaceWith( newlist );
                                commentbox = $( commentbox_name );
                                ajaxCommentsTrigger();
                                $('html, body').animate({
                                    scrollTop: $( '#' + reply ).offset().top
                                }, 500);
                            });
                        }
                    } else {
                        statusdiv.html('<div class="ajax-error">エラーが発生しました。ウェブマスターにご連絡ください。</div>');
                        return false;
                    }
                } else {
                    statusdiv.html('<div class="ajax-error">エラーが発生しました。時間をおいて再度送信して下さい。</div>');
                    return false;
                }
            }).fail(function(data){
                statusdiv.html('<div class="ajax-error">送信が中断されました。<strong>記入もれや間違いがないか</strong>再度ご確認ください。</div>');
            });
        });
    }

    function ajaxCommentsTrigger(){
        var replybox = $( '<div id="reply-box"></div>' ),
            commentform = $( commentform_name, commentbox );
        commentform.clone( true ).appendTo( replybox );
        replybox.find( '[id]' ).each(function(){
            $(this).prop('id', 'reply-' + $(this).attr( 'id' ) );
        });
        ajaxComments( commentform );
        ajaxComments( replybox.children( 'form' ) );
        $( 'a.comment-reply-link', commentbox ).click(function(e){ 
            e.preventDefault();
            var replylink = $(this), list = replylink.parents( 'li.depth-1' );
            if ( list.hasClass( 'replying' ) ){
                list.removeClass( 'replying' );
                replylink.html( '返信する' );
                replybox.slideUp( 500 );
            } else {
                list.addClass( 'replying' );
                list.siblings('.replying').removeClass( 'replying' ).find( 'a.comment-reply-link').html( '返信する' );
                replylink.html( '返信をキャンセル' );
                var parentid = list.attr('id').slice(8); // ex:#comment-999
                replybox.find( '#reply-comment_parent' ).val( parentid );
                replybox.hide().appendTo( list ).slideDown( 500 );
            }
        });
    }
});
</script>
<?php
endif;
}
add_action('wp_footer', 'ajaxify_comments_script');
?>

このサンプルコードではfunctions.phpに記載することを前提にwp_footerにフックしてますが、jQueryだけで完結してるんでjs部分をテンプレートに直書きしてもOKです。動作はここのフォームでコメントなしで送信ボタンを押せば、エラーが返ってきますのでどうぞ。ちなみに前記事「Really Simple CAPTCHAをコメント欄に応用する。」も併用できます。

 

どうやってヴァリデートするか、が肝なのかも。

ajaxでpostするところまではどのプラグインでも動作は大体同じ。コメントのヴァリデーション方法については作者毎に個性があるが、comment_postにフックしてajax時のみ処理を分岐させて云々…というのが常道のようだった。それで良いのだけども、結局、コメント投稿に失敗したときに返ってくるエラーページを読み込んでPOSTの可否を判断することにした。htmlソースで判断することの是非はあるかもしれないが、フック処理が不要になるしwordpressのエラーメッセージを流用できるので、関数をシンプルに保てて、保安上もメリットになると思えたからだ。

もうひとつの大きな設計判断としては、コメント後にユーザーにだけ見えるモデレート待ち のコメントを表示する方法をどうするかだけども、これはコメントが通過後に返ってくる新しいポストから#commentsタグを抽出して丸ごと差し替えること にした。キャプチャを使用している場合にはその更新が必要だったり、コメントテンプレートのデザインやソートがテーマ毎にまちまちだったりするので、コメントテンンプレートをまるごと差し替えるのが現実的だろうというわけです。

おまけ:ここで適用してるcss

ajaxは思いの外時間がかかることもあるので、css 3のアニメーションなどを活用してユーザーを迷わせないよう設計することが大事ですね。

.comment-ajax { margin:5px 0; }
.comment-ajax > div { padding:5px 10px; font-size:16px; }
.ajax-error { background:#356; color:#fff; }
.ajax-success { background:#2bb; color:#fff; } 
.ajax-processing { position:relative; background:#eee; } 
.ajax-processing:before { width:100%; display:block; content:' '; margin:0; padding:0; background:#a9e3e4; position:absolute; height:3px; left:0; bottom:0; -webkit-animation:fullexpand 1.5s ease-out; z-index:1; animation:fullexpand 1.5s ease-out; }
@-webkit-keyframes fullexpand { 0%  { width:0;} 100%{ width:100%;} }
@keyframes fullexpand { 0% { width:0;} 100%{ width:100%;} }

「wordpressのコメント欄をajax化する。」への20件の返信

  1. 参考にさせていただきました。

    尚、以下の行でエラーが出て動きませんでしたのでシングルクォートないしダブルクォートで囲いました。
    var matches = data.match(/([sS]*?)/);

    var matches = data.match(‘/([sS]*?)/’);

  2. 成功するときと失敗するときがあり、失敗するとURLの末尾に「#undefined」が付いて、commentsのdivがごっそり消え去ります。

    どうすれば。。。。

    1. ご報告ありがとうございます。

      undefinedを区別するように上記のjsを修正しました。

      commentsのdivが消えるのは、ポストはうまくいったにもかかわらずjsの処理が失敗しているせいです。
      undefinedの発生原因は、ajaxの読み出し先に誤ったhtmlタグなどがあるって失敗している可能性が高いのではないかと推測します。処理はphpなのでコメントがなくなるわけではないです。動作が改善しない場合は、テンプレートを見直すか、コメントIDを取得するタイプのajaxプラグインを使う必要があるかもしれません。
      undefinedが帰ってきた場合、ページをロードするようなjsの仕掛けをするのもいいかもしれませんね。承認待ちなどのシステムを活用していると、コメントが現れず不安を覚えて重ねて投稿、ということもあるかもしれませんので。そのうち考えます。

  3. 一番最初のコメント投稿だと、#commentsごと消えてしまいます。

    。。

  4. こんにちは!

    素晴らしいコードありがとうございます!
    一つ質問があるのですが、メッセージを表示させる場所を変更するには
    どうしたら良いのでしょうか?
    お手すきの間にでもご教示頂けると幸いです。

    1. var statusdiv = $('<div class="comment-ajax"></div>');

       
       this_form.prepend( statusdiv ).......

      上記の箇所で、div.comment-ajaxをフォームに対してprepend(先頭)に挿入しています。appendに変更してフォームの後方に入れるか、そもそもjsは触らなくて済むように、cssでポジションを指定するのが一番簡単な改変方法です。

    2. さっそくの返信ありがとうございます!

      appendにしてさらにCSSで調整することにしました。
      JSは全然わからなかったので助かりました〜m(_ _)m
      これを機に勉強してみようと思います。
      ありがとうございます。

匿名 へ返信する コメントをキャンセル

メールアドレスが公開されることはありません。 が付いている欄は必須項目です