워드프레스 방식의 더 흔한 jQuery ajax 폼 메일, admin-ajax.php

워드프레스 방식의 폼 데이터 처리 방식으로 Html 폼 작성, 폼 데이터 검증, 메일 발송 방법에 관하여 워드프레스 폼 데이터 처리 방식으로 메일 전송 폼 직접 만들고 Contact Form 7 그만 쓰기 포스트에서 간단하게 살폈습니다. 이번에는 워드프레스 방식의 ajax 요청으로 폼 데이터를 메일로 전송해봅니다.

이 포스트에서는 지난 포스트의 최종 파일에서 일부 요소를 변경하고, ajax 요청에 관한 자바스크립트 코드를 추가합니다. 다음은 지난 포스트의 최종 파일 페이지입니다.

위 파일 기준으로 이어갑니다.

admin-post.php

일반적인 POST, GET 요청에 관한 워드프레스 폼 데이터 처리 과정은 폼 액션 URL과 폼 데이터에 action(name)과 값을 지정하여 전달하는 것이 핵심입니다.

// 24번 줄
<form id="sendmail_form" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="POST">
// 42번 줄
<input type="hidden" name="action" value="sendmail_formdata">

그리고, 폼 데이터 처리를 위한 훅을 다음 유형으로 지정하는 것으로 끝입니다. 데이터 검증 등의 나머지는 사용자 의도에 따른 것이므로 기준은 아닙니다.

// admin_post_{action_value}, admin_post_nopriv_{action_value}
add_action( 'admin_post_nopriv_sendmail_formdata', 'func_sendmail_formdata' );
add_action( 'admin_post_sendmail_formdata', 'func_sendmail_formdata' );

admin-ajax.php

지난 파일을 기준으로 워드프레스 방식의 ajax 요청을 위해서는 URL 액션만 제거하면 됩니다. 폼 아이디(id)는 원하는 것으로 정하면 됩니다.

// 파일 24번 줄을 다음으로 변경
<form id="ajax_sendmail_form" method="POST">

다음으로 워드프레스 ajax 요청 훅을 다음처럼 변경합니다. 훅 유형을 보면 더 설명할 필요가 없습니다.

// wp_ajax_{action_value}, wp_ajax_nopriv_{action_value}
add_action( 'wp_ajax_nopriv_sendmail_formdata', 'func_sendmail_formdata' );
add_action( 'wp_ajax_sendmail_formdata', 'func_sendmail_formdata' );

이렇게 하면 폼 데이터 제출 시 전달 경로가 없는데, 자바스크립트 코드에서 추가해야 합니다. 그 경로는 다음과 같습니다.

domain/wp-admin/admin-ajax.php

자바스크립트에 관한 내용은 마지막에 추가하기로 하고, Html 폼과 폼 데이터 처리에 관한 부분을 먼저 완료합니다.

Html 폼

먼저, 요청에 의한 응답 메시지 출력을 위한 블록을 추가하고, 자바스크립트 selector로 사용할 블록 아이디와 클래스를 추가 및 변경한 Html 폼 변경 전체 소스는 다음과 같습니다.

add_shortcode( 'ajaxmailform', 'custom_ajaxform_creation' );
function custom_ajaxform_creation(){
    ob_start();
?>
<div class="ajaxform" style="margin-bottom: 2em">
    <form id="ajax_sendmail_form" method="POST">
        <p>모든 입력 필드는 반드시 입력해야 하며, 인용기호는 사용할 수 없습니다. 한 번 보낸 후 다시 보내려면 일정 시간이 지나야 합니다.</p>
        <p>
            <label for="ftitle">문의에 관한 주제를 입력하세요</label>
            <input type="text" id="ftitle" name="ftitle" placeholder="제목" required>
        </p>
        <p>
            <label for="fname">이름 또는 단체명</label>
            <input type="text" id="fname" name="fname" placeholder="이름" required>
        </p>
        <p>
            <label for="femail">이메일 주소를 바르게 입력하세요</label>
            <input type="email" id="femail" name="femail" placeholder="이메일" required>
        </p>
        <p>
            <label for="fcontent">내용을 입력하세요</label>
            <textarea type="textarea" id="fcontent" name="fcontent" maxlength="3000" rows="8" placeholder="줄 바꿈, 단락(빈 줄) 구분만 가능하며, 최대 글자 수 제한이 있습니다. (3000)" required></textarea>
        </p>
        <input type="hidden" name="action" value="sendmail_formdata">
        <?php wp_nonce_field( 'sendmail_formdata', 'sendmail_formdata_field' ); ?>
        <button type="submit" class="submit">보내기</button>
    </form>
</div>
<div class="msg"></div>
<?php
    return ob_get_clean();
}

위의 코드 6, 29번 줄의 변경 및 추가 내용에 초점을 두면 되고, 일부 요소의 이름이 변경되었는데 핵심은 아닙니다.

워드프레스 8 - 무료 이미지 저장소

폼 데이터 처리 및 응답 메시지

지난 파일을 보면 wp_die 함수를 사용한 폼 처리 결과 메시지를 정의한 곳이 있습니다. 모두 네 군데인데, ajax 요청 응답에 관한 워드프레스 함수를 사용하여 모두 변경합니다. 일부 코드를 제외하면 다음과 같습니다.

add_action( 'wp_ajax_nopriv_sendmail_formdata', 'func_sendmail_formdata' );
add_action( 'wp_ajax_sendmail_formdata', 'func_sendmail_formdata' );
function func_sendmail_formdata() {

    //

    if ( get_transient( $transient ) ) {
        wp_die( wp_send_json_error( array ( 'message' => '한 번 보내면 ' . absint( $delay ) . '분 후에 다시 보낼 수 있습니다.' ) ) );
    }

    //

        //

        if ( $success_req ) {
            //

            wp_die( wp_send_json_success( array( 'message' => '메일 전송 요청 성공! 고맙습니다.' ) ) );
            // wp_die( wp_send_json_success( array( 'message' => '메일 전송 요청 성공! 고맙습니다.', 'content' => $body ) ) );

        } else {

            wp_die( wp_send_json_error( array( 'message' => '메일 전송에 오류가 있었습니다. 나중에 다시 해보세요.' ) ) );

        }

    } else {

        wp_die( wp_send_json_error( array( 'message' => '빠진 데이터가 있거나 올바른 방법이 아니군요.' ) ) );

    }
    
}

사용한 함수들은 ajax 요청에 관한 응답 결과를 전달하는 것으로 간단하므로 따로 안내하지 않습니다. 코덱스를 참고하거나 이 포스트의 결과를 확인하는 것으로 충분합니다.

이제 ajax 요청에 의한 폼 데이터 전달 및 응답 결과 출력하는 자바스크립트 코드만 정의하면 됩니다. 포스트에서는 jQuery를 사용합니다.

Ajax 요청에 의한 폼 데이터 전송

파일 맨 아래에 기본적인 jQuery ajax 요청 패턴을 다음처럼 정의합니다.

add_action( 'wp_footer', 'ajax_form_script' );
function ajax_form_script() {
    ?>
    <script type="text/javascript">
        ( function( $ ) {
            $( '#ajax_sendmail_form' ).on( 'submit', function( event ) {
                event.preventDefault();
                var ajax_form_data = $( '#ajax_sendmail_form' ).serialize(); // serialize the form data
                $.ajax( {
                    // url: ajaxurl, // localhost/wp-admin/admin-ajax.php
                    url: '<?php echo esc_url( admin_url('admin-ajax.php') ); ?>',
                    type: 'POST',
                    data: ajax_form_data,
                    success: function( response ) {
                        $( '.msg' ).html( response.data.message );
                    }
                } )
            } );
        } )( jQuery );
    </script>
    <?php
}

위의 8번 줄에서 폼 데이터 전체를 시리얼 데이터로 변수에 할당하여 11번 줄의 워드프레스 ajax 요청에 의한 데이터 처리 경로에 전달합니다.

9번 줄에서 17번 줄은 다음과 같은데, 폼 데이터를 전달하고, 응답 메시지를 받는 코드입니다.

$.ajax( {
    // url: ajaxurl, // localhost/wp-admin/admin-ajax.php
    url: '<?php echo esc_url( admin_url('admin-ajax.php') ); ?>',
    type: 'POST',
    data: ajax_form_data,
    success: function( response ) {
        $( '.msg' ).html( response.data.message );
    }
} )

6번 줄은 ajax 요청 연결 성공을 뜻하며, 폼 데이터 내부 처리에 관한 성공 또는 오류 등을 말하지 않는다는 것을 기억하면 됩니다. 따라서, 폼 데이터 처리와 관련한 응답 메시지는 7번 줄 하나로 충분합니다.

요청 URL

위의 3번 줄 대신에 2번 줄의 ajaxurl 자바스크립트 변수를 사용해도 됩니다. 이 변수는 워드프레스 관리페이지 또는 프런트 페이지에 항상 출력되는 것으로, 다음처럼 소스에 출력됩니다. 도메인은 상대적입니다.

<script type="text/javascript">
    var ajaxurl = 'http://localhost/wp-admin/admin-ajax.php';
</script>

보통은 사용자가 추가한 플러그인 또는 기능을 구현할 때, 결론적으로는 같은 URL(도메인 제외)이지만, 별도로 정의하는 때가 많습니다. 이 포스트에서는 함수를 이용한 것뿐이며, 다른 의도는 없습니다.

action, nonce

이 포스트에서는 Html 폼에 actionnonce 데이터를 포함하였기에 자바스크립트에서 별도로 추가하지 않았으며, 폼 데이터 ajax_form_data 변수에 모두 포함되어 전송되므로 따로 정의할 필요가 없습니다. 만약, 폼에서 추가하지 않는다면 다음처럼 자바스크립트 ajax 요청에 추가하면 됩니다.

$.ajax( {
    url: '<?php echo esc_url( admin_url('admin-ajax.php') ); ?>',
    type: 'POST',
    data: ajax_form_data,
    action: sendmail_formdata,
    nonce: '<?php wp_create_nonce( "ajax-form-nonce" ); ?>'
    success: function( response ) {
        $( '.msg' ).html( response.data.message );
    }
} )

이때 nonce 검증에 관하여 다음의 함수를 사용한 코드 편집이 필요할 수 있으며, 설명은 생략합니다. 변경 후에는 시험하여 올바르게 적용되는지 확인해야 합니다.

if ( check_ajax_referer( 'ajax-form-nonce', 'nonce', false ) == false ) {
    wp_send_json_error();
}

폼에 nonce 데이터를 포함할 때 자바스크립트에 nonce 데이터를 따로 추가하지 않는 게 좋습니다. 폼에 추가한 nonce 데이터 및 wp_verify_nonce 함수를 통한 검증은 자바스크립트에 추가한 nonce 데이터를 check_ajax_referer 함수로 검증한 것과 다르지 않습니다.

페이지 내 자바스크립트와 파일로 분리

이 포스트는 자바스크립트 코드를 wp_footer 훅을 사용하여 페이지 내에 추가하였습니다. 위의 코드를 별도의 파일을 만들어 추가한다면 스크립트 대기열 등록 훅을 사용하여 다음처럼 정의할 수 있습니다. 코드는 예를 든 것으로 파일 이름 등은 관련이 없습니다.

add_action( 'wp_enqueue_scripts', 'custom_enqueue_script' );
function custom_enqueue_script() {
        
    wp_enqueue_script( 'ajax-script', get_template_directory_uri() . '/js/script.js', array( 'jquery' ), '', false );
    // wp_enqueue_script( 'ajax-script', plugins_url( '/js/script.js', __FILE__ ), array('jquery') );

}

또, 자바스크립트에 사용할 admin-ajax.php 경로와 nonce 데이터를 wp_localize_script 함수를 사용하여 추가할 수 있습니다.

add_action( 'wp_enqueue_scripts', 'custom_enqueue_script' );
function custom_enqueue_script() {
        
    wp_enqueue_script( 'ajax-script', get_template_directory_uri() . '/js/script.js', array( 'jquery' ), '', false );
    // wp_enqueue_script( 'ajax-script', plugins_url( '/js/script.js', __FILE__ ), array('jquery') );

    wp_localize_script( 'ajax-script', 'ajax_object', array(
        'ajax_url' => admin_url( 'admin-ajax.php' ),
        'nonce' => wp_create_nonce( 'ajax-form-nonce )
    ) );
}

어떤 것이 좋다는 기준은 없으므로 사용자의 판단과 구성 기능에 따라 효율성을 우선으로 두면 됩니다. 이 포스트는 사실, 설명의 편의를 위해 하나의 파일로 처리한 것입니다.

워드프레스 Ajax 폼 완성 파일

다음 링크의 페이지에서 이 포스트의 완성 파일을 받을 수 있습니다. 간단한 플러그인 형식으로 구성한 것이며, 자바스크립트 코드에는 jQuery 일부 API를 사용하여 과정에 따른 폼 변화를 정의한 부분이 있습니다. 이 포스트의 핵심 내용은 아니므로 설명은 생략합니다.

다음 그림은 완성 파일을 사용하여 폼 데이터를 전송하고, 응답 메시지를 출력하는 최종 결과입니다.

워드프레스 Ajax 폼 Success 응답 메시지

다음 그림은 재전송 시간이 지나지 않은 때 응답 메시지입니다.

워드프레스 Ajax 폼 Error 응답 메시지

이 포스트 완성 파일을 열어 보면 107, 108번 줄에 다음 2, 3번 줄이 있습니다. 다음 2번 줄 비활성, 3번 줄 활성화 후 145번 줄 활성화하면 ajax 요청 응답에 폼에 입력한 데이터를 출력할 수 있습니다.

// 107, 108번 줄
wp_die( wp_send_json_success( array( 'message' => '메일 전송 요청 성공! 고맙습니다.' ) ) );
// wp_die( wp_send_json_success( array( 'message' => '메일 전송 요청 성공! 고맙습니다.', 'content' => $body ) ) );
// 145번 줄
// $( '#ajax_sendmail_form' ).html( response.data.content );

정리

워드프레스 시스템에서 특정 기능을 구현할 때 워드프레스에서 제공하는 함수, 방식 등을 먼저 검색하여 파악하면 상대적으로 구현이 쉬울 때가 많습니다. 폼 데이터 전송, 검증, 데이터 처리, 저장 등의 과정이 그에 포함됩니다.

이 포스트에서 폼 데이터 처리 등의 내용은 이미 다음의 지난 포스트에서 안내하였기에 생략했는데, 실제 그 내용이 더 많은 시간을 요구합니다. 한 번 둘러보세요.

위의 2번째 포스트의 완성 파일에 있는 ‘폼 데이터 포스트 저장’ 코드만 그대로 이번 포스트의 완성 파일에 추가하면 ajax 요청에 의한 폼 데이터도 포스트로 저장할 수 있습니다. 참고하세요.

어떤 의견이 있거나 궁금한 무언가 있다면 다음 링크의 사이트를 이용하세요.

이메일로 소식 받기

이메일로 새로운 포스트를 받으려면 아래에 이메일 주소를 입력하고, 구독합니다! 버튼을 클릭하세요. 그리고 입력한 이메일 계정에 접속하여 구독 확인 메일 내용을 확인하세요.