워드프레스에서 웹 요청 처리하기

워드프레스를 사용하다보면 종종 사용자로부터 어떤 데이터를 입력받아야 할 경우가 생깁니다. 예를 들면 컨택폼(contact form) 같은 양식으로 사용자 정보를 받거나 아니면 사용자가 직접 사이트에 콘텐츠를 입력할 수 있게 해야 할 경우 등입니다. 워드프레스 사용자라면 이럴 경우 맨 먼저 플러그인을 떠올릴 것입니다. 워드프레스 플러그인 중에는 사이트에 컨택폼을 추가하거나 사용자 입력 폼을 추가할 수 있게 해주는 다양한 플러그인들이 존재합니다. 이들 플러그인 중 하나를 골라 설치하면 간단하게 해결됩니다.

— 참고: 워드프레스 폼 빌더 플러그인

하지만 종종 이런 플러그인만으로는 부족한 경우가 생길 수 있습니다. 또는 플러그인 없이 직접 구현할 필요가 있을 수도 있구요. 이럴 경우에 워드프레스의 기본 기능들만 이용하여 간단하게 웹 폼을 만들고 저장하는 방법을 소개하는 것이 이 글의 내용입니다.

사용자 입력폼 만들기

우선 다음과 같은 사용자 입력폼을 간단하게 한번 만들어 보기로 하겠습니다. 워드프레스 4.7 버전 기준이며, 테마는 4.7의 기본 테마인 Twenty Seventeen을 사용합니다.

사용자 입력 폼 UI

이 페이지는 페이지 내에 PHP 코드를 집어 넣을 수 있어야 하기 때문에 페이지 템플릿(Page Templates)을 만들어야 합니다. 여기서는 템플릿 계층 구조에 입각한 파일명으로 페이지 템플릿을 만들 것이기에 템플릿 파일명을 page-user-form.php 라고 주겠습니다 (파일명을 페이지의 slug값과 일치시키기만 하면 뭐든 상관없습니다).

이렇게 만든 페이지 템플릿(page-user-form.php)을 테마의 레이아웃과 맞추고 본문이 들어갈 자리에 다음과 같이 폼 코드를 입력합니다.

<form action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="post" id="userForm">
  <input type="hidden" name="action" value="user_form">
  <?php wp_nonce_field( 'user_form' ); ?>
  <p><label for="form-title">제목:
    <input type="text" name="title" id="form-title">
  </label></p>
  <p><label for="form-text">본문:
    <textarea name="text" id="form-text" rows="8" cols="40"></textarea>
  </label></p>
  <p><input type="submit" value="저장하기"></p>
</form>

코드에 대해 몇 가지만 부연하면,

  1. form의 action 값에는 admin-post.php를 지정하였습니다 (이유는 나중에 뒤에서 설명합니다).
  2. hidden 태그로 action 값에 ‘user_form’을 두었습니다 (이 부분도 나중에 설명).
  3. wp_nonce_field 템플릿 태그로 폼에 Nonce 값을 추가합니다. 알다시피 Nonce는 워드프레스에서 크로스 사이트 요청 위조(CSRF) 공격에 대한 방어 장치입니다.

폼 요청 처리하기

폼으로부터 받은 POST 데이터를 처리하는 부분입니다. 여기서는 폼값을 워드프레스 Post로 저장하는 간단한 처리를 하도록 하겠습니다.

폼 데이터를 입력받아 처리하는 부분은 워드프레스라고 해서 여느 다른 프로그램 언어들과 다를 바 없습니다. 또한 워드프레스가 PHP 기반이기 때문에 통상적인 PHP의 폼 처리 방식 — 예를 들면, 템플릿 파일 내에서 직접 $_POST 값을 받아 처리 — 으로도 충분히 가능합니다만, 여기서는 워드프레스가 정해 놓은 소위 ‘워드프레스 방식(WordPress Way)’을 따르기로 하겠습니다.

워드프레스에서는 위와 같은 웹 요청을 처리하기 위한 용도로 사용할 수 있는 종단점(endpoint)을 제공합니다. 바로 admin-post.php 라는 파일입니다. 워드프레스로 향하는 모든 웹 요청(GET 또는 POST)은 이 종단점을 타겟으로 지정하고, ’admin_post_(action)’이라는 액션 훅을 통해 요청에 대한 처리를 할 수 있도록 해 두었습니다. 앞서 우리가 사용자 폼에서 action 값으로 admin-post.php를 지정한 것은 바로 그 때문입니다. 이렇게 admin-post.php를 호출할 때 action 값을 함께 넘기는 방식으로 여러 호출을 구분할 수 있게 됩니다. 우리의 경우 action 값으로 ‘user_form’ 이라는 값을 주었습니다.

실제로 폼을 처리하는 부분의 코드는 다음과 같습니다.

function demo_process_user_form() {

  check_admin_referer( 'user_form' );

  // Server-side form validation goes here

  $title = $_POST['title'];
  $text = $_POST['text'];

  $post = array(
    'post_title' => $title,
    'post_content' => $text,
    'post_type' => 'post',
    'post_status' => 'publish' // 'pending'    
  );

  $post_id = wp_insert_post($post);

  if ( $post_id ) {
    wp_redirect( home_url() );
    exit;    
  }    
}

add_action( 'admin_post_user_form', 'demo_process_user_form' );

코드에 대해 몇 가지만 부연하면,

  1. check_admin_referer() 함수를 호출하여 Nonce 값을 검증합니다.
  2. 폼값은 $_POST 변수로 받아서 처리합니다. 여기서는 폼값에 대한 검증(validation) 처리는 생략하지만, 실제로는 반드시 처리할 부분입니다.
  3. add_action 함수에서 ‘admin_post_user_form’ 이라는 액션 훅을 사용합니다. 앞서 우리가 폼에서 action 으로 ‘user_form’ 이라는 값을 넘겨 주었기에, 관례에 따라 여기서 ‘admin_post_user_form’ 이라는 액션 훅이 호출됩니다.

AJAX 요청 처리하기

간단하게 웹 요청을 받아 처리하는 것이라면 여기까지가 끝입니다. 그런데 여기서 한걸음 더 나가 보기로 하겠습니다. 이번엔 웹 요청을 단순 HTTP POST 방식이 아닌 Ajax로 호출하기로 해 보겠습니다.

이미 예상했겠지만, 앞서 admin-post.php와 마찬가지로 워드프레스는 Ajax 호출에 대비해 admin-ajax.php 라는 종단점을 제공합니다. Ajax 호출의 종단점을 admin-ajax.php로 지정하고 워드프레스에서 ‘wp_ajax_(action)’ 액션 훅으로 받아 처리하는 부분은 앞의 POST 요청 처리와 전혀 다르지 않습니다.

그럼 우선, 앞서 만든 사용자 입력폼을 Ajax 호출 방식으로 변경해 보기로 하겠습니다. 테마의 자바스크립트 파일을 열어 다음과 같이 간단하게 코드를 추가합니다.

$('#userForm').submit(function(e) {
  e.preventDefault();
  var $form = $(this);
  var url = '/wp-admin/admin-ajax.php';
  $.post(url, $form.serialize(), function(data) {
    // console.log(data);
  });
});

코드는 jQuery를 이용한 간단한 Ajax 호출을 구현한 것입니다. 여기서 Ajax 호출의 종단점을 admin-ajax.php로 지정한 것을 확인할 수 있습니다.

이제 워드프레스 측으로 넘어와서 이 종단점에 대한 액션 훅만 처리하면 됩니다. 예상한 대로 액션 훅은 다음과 같습니다.

add_action( 'wp_ajax_user_form', 'demo_process_user_form' );
add_action( 'wp_ajax_nopriv_user_form', 'demo_process_user_form' );

여기서는 설명의 편의상, 훅과 매핑하는 실행 코드는 앞서 POST 요청 처리에서 사용한 demo_process_user_form() 함수를 재사용하였습니다만, 실제로는 Ajax 요청의 반환 처리 등을 위해 통상적인 HTTP 폼 요청과는 조금 다른 로직으로 작성해야 할 것입니다. 또한 위에서 wp_ajax_user_form 액션과는 별도로 wp_ajax_nopriv_user_form 액션을 둔 것은 워드프레스가 로그인한 상태와 그렇지 않은 상태를 각각 구분해서 액션 훅을 처리하기 때문입니다.

wp_localize_script

앞서 Ajax을 호출하는 자바스크립트 코드에서는 종단점인 admin-ajax.php 를 코드 속에 직접 하드코딩하는 방식으로 처리하였지만 실제로 이렇게 하는 것은 바람직한 방법이 아닙니다. 워드프레스에서는 wp_localize_script 라는 함수를 통해 워드프레스에서 클라이언트측으로 필요한 변수들을 전달할 수 있는 메커니즘을 제공합니다 (원래 이 함수의 용도는 이름 그대로 로컬라이제이션을 처리할 목적이지만 지금처럼 서버측 데이터를 클라이언트와 공유할 때도 유용하게 사용됩니다).

이 함수를 워드프레스 테마의 wp_enqueue_scripts 액션에 다음과 같이 추가하면,

$config_array = array(
  'ajaxURL' => admin_url( 'admin-ajax.php' ),
  'ajaxNonce' => wp_create_nonce()
);

wp_localize_script( 'twentyseventeen-global', 'myConf', $config_array );

앞서 jQuery를 이용한 Ajax 호출 부분은 다음과 같이 구성할 수 있게 됩니다(url을 하드코딩하는 대신 워드프레스로부터 받은 myConf 라는 객체로부터 종단점의 url값을 얻어 옵니다).

$.post(myConf.ajaxURL, $form.serialize(), function(data) {
  // console.log(data);
});

이 때 myConf로부터 넘겨 받는 값은 굳이 admin_url로 한정될 필요는 전혀 없습니다. 여기서는 워드프레스가 생성한 nonce 값도 ajaxNonce라는 이름으로 넘겨 받고 있습니다. 실제로는 이 값을 Ajax 호출 시에 함께 넘겨 주면 좋을 것입니다.

오늘은 여기까지 입니다. 🙂

0 thoughts on “워드프레스에서 웹 요청 처리하기”