워드프레스 폼 플러그인 중에는 폼 데이터를 메일로 보내면 그만인 것이 있고, 메일도 보내고 포스트 데이터로도 저장하는 플러그인이 있습니다. 물론, 메일만 보내는 플러그인도 애드온 등의 플러그인을 사용하면 포스트로 저장할 수 있습니다.
메일 발송과 함께 포스트로 저장하는 대표 플러그인으로 Jetpack의 Contact Form 모듈이 있습니다. 다음 그림처럼 폼 데이터 목록을 볼 수 있는데, 해당 포스트 타입 이름은 feedback
(피드백)입니다. 새로운 포스트 타입에 폼 데이터를 저장한다는 뜻입니다.
피드백 포스트 편집 화면에 접근하면 다음 그림의 형태로 폼 데이터를 저장하는 것을 볼 수 있습니다.
이처럼 폼으로 받은 데이터를 메일로 보내는 것과 함께 원하는 데이터 유형의 워드프레스 포스트로 저장한다면 데이터 활용 기회를 확보할 수 있습니다. 폼 데이터는 보통의 포스트 콘텐츠 유형과 메타 데이터가 아니라 하나의 필드에 시리얼 데이터로 저장하면 때로 편리할 수 있습니다. 물론, 절대적인 것은 아니며, 자유입니다.
이 포스트에서는 지난 워드프레스 폼 데이터 처리 방식으로 메일 전송 폼 직접 만들고 Contact Form 7 그만 쓰기 포스트의 완성 파일을 기준으로 폼 데이터를 저장해봅니다. 따라서, 다음 링크 페이지에서 파일을 받아 열어 놓고 확인해야 합니다.
또, 파일은 간단한 플러그인 형식으로 정의한 것이므로 업로드 방식으로 플러그인을 설치한 후 진행해야 이해를 더할 수 있습니다. 파일을 받고 설치 후 활성화한 상태를 기준으로 이어갑니다.
폼 데이터 저장
다음 그림은 Shortcode 삽입으로 출력한 폼이 있는 page
타입 포스트의 사이트 화면으로, 각 필드에 데이터를 입력하고 보내기 버튼을 클릭하면 폼 데이터를 메일로 받을 수 있습니다.
이때, 메일 발송 외에 데이터를 post
타입에 저장하려면 메일 요청 성공 후 단계에서 포스트 저장 코드를 추가하면 됩니다. 다음 코드는 메일 요청 성공 후 만료 기간이 있는 transient
데이터를 생성하여 일정 시간이 지나야 폼 데이터를 전송하도록 정의한 것입니다.
if ( false === ( $form_ticket = get_transient( $transient ) ) ) {
$form_ticket = wp_generate_password( 24, false, false );
set_transient( $transient, $form_ticket, $delay * MINUTE_IN_SECONDS );
}
위 코드를 찾아 위의 코드 4번 줄 위치에 다음 아래의 코드를 추가하면 폼 데이터를 formfeed
커스텀 포스트 타입에 저장할 수 있습니다. 아직 formfeed
포스트 타입은 정의하지 않았으므로 post
로 변경하고 저장 후 시험하면 추가된 데이터를 관리페이지에서 볼 수 있습니다.
// Insert Post
$parent_post_id = absint( url_to_postid( $_SERVER['HTTP_REFERER'] ) ); // 폼 삽입한 싱글 포스트 ID.
$post_content = array(
'제목' => $subject,
'이름' => $name,
'메일' => $email,
'내용' => $content,
'시각' => $time,
'아이피' => $user_ip,
'페이지' => $_SERVER['HTTP_REFERER'],
'그룹' => ( $parent_post_id ) ? $parent_post_id : ''
);
$post_id = wp_insert_post(
array(
'post_title' => $subject,
'post_content' => maybe_serialize( $post_content ),
'post_status' => 'publish',
'post_type' => 'formfeed',
'post_name' => wp_generate_password( 24, false, false ),
'post_parent' => $parent_post_id,
'post_author' => 0,
)
);
2번 줄은 폼을 삽입한 포스트의 ID
를 URL 정보 기준으로 구하기 위해 url_to_postid
함수를 사용한 것입니다. 이 포스트는 아니지만, 서로 다른 범위(주제)의 데이터를 수집하는 폼이 많을 때 폼 삽입 포스트 페이지가 범위의 기준이라면 그 페이지 정보를 데이터로 저장하여 데이터 구분과 관리에 도움을 줄 수 있습니다. 22번 줄에서 폼 삽입한 싱글 포스트 ID를 post_parent
필드에 추가한 것도 같은 뜻으로 추가한 것입니다.
12번 줄은 아카이브 페이지 등의 싱글 포스트 페이지가 아닐 때 위젯에 출력한 폼에서 폼 데이터를 저장하는 때를 가정한 것입니다.
15번 줄의 wp_insert_post
함수는 워드프레스 포스트를 추가하는 기본이자 핵심 함수입니다. 이 함수는 워드프레스 포스트 콘텐츠 등록에 관한 많은 단계를 포함하고 있으므로 워드프레스 기본 시스템에 의한 포스트 등록이 아닐 때 꼭 사용하여 괜히 불필요한 과정으로 고생하지 않는 게 좋습니다.
18번 줄에서 maybe_serialize
함수를 사용하여 폼 데이터 전체가 있는 $post_content
변수의 배열 데이터를 시리얼 데이터로 post_content
필드에 저장합니다. 폼의 각 필드 데이터를 포스트의 메타 데이터로 저장해도 되며 방법은 만드는 사람 마음입니다.
21번 줄 post_name
은 보통 포스트 슬러그로 부르는 데이터입니다. 포스트 주소에서 URL 제외한 퍼머링크로 고유한 값이어야 합니다. 폼 데이터를 저장한 포스트는 관리자만 관리페이지에서 보는 것을 기준으로 정하기에 무작위 코드로 생성하도록 정의한 것입니다. 이 포스트에서는 의미가 없는 데이터이며, 혹시 중복이라면 워드프레스가 자동으로 숫자를 붙여 추가하므로 염려하지 않아도 됩니다.
커스텀 포스트 타입 formfeed 등록
폼 데이터를 formfeed
이름의 포스트 타입에 포스트로 추가하도록 설정했으므로 해당 포스트 타입을 등록해야 합니다. 이 포스트에서 폼 데이터를 위한 formfeed
포스트는 다음의 몇 가지 주요 기준으로 정의합니다.
- 비공개 포스트
- WP REST API 등록 제외
- 관리페이지에서 목록으로 내용 확인
- 편집 화면 접근 경로 제거
위의 기준을 적당히 맞추기 위해 다음과 같이 커스텀 포스트 타입을 정의합니다. 플러그인 파일 맨 아래에 이어서 추가하면 됩니다.
add_action( 'init', 'register_formfeed_cpt', 0 );
function register_formfeed_cpt() {
register_post_type( 'formfeed', array(
'labels' => array(
'name' => '문의',
'singular_name' => '문의',
'menu_name' => '문의',
),
'capabilities' => array(
'create_posts' => false, // 새 글 쓰기 불가
),
'map_meta_cap' => true,
'public' => false,
'show_ui' => true,
'show_in_menu' => true,
'show_in_nav_menus' => false,
'exclude_from_search' => true, // 's' query var 제외
'has_archive' => false,
'rewrite' => false,
'query_var' => false,
'capability_type' => 'post', // capability type 'post'. 포스트 타입 'post' 아님
'menu_icon' => 'dashicons-format-aside',
'menu_position' => 3,
'supports' => array( 'title', 'editor' ),
'show_in_rest' => false // WP REST API, Gutenberg edit disable
) );
}
커스텀 포스트 타입과 등록에 관한 내용은 워드프레스 사용자라면 한 번은 직접 학습해야 워드프레스 사용으로 얻는 이익이 늘어나므로 긴 설명은 생략하고 몇 가지만 안내합니다.
9번 줄에서 13번 줄은 정의하는 포스트 타입의 권한에 관한 설정입니다. 13번 줄은 포스트 타입 post
가 아니라 Capability 타입 post
로, 기본 포스트 타입 post
에는 기본 Capability 타입 post
가 할당되어 있습니다. 그 Capability 타입 post
를 커스텀 포스트 타입 formfeed
에 사용한다는 것입니다.
따라서, formfeed
커스텀 포스트 타입에 관한 권한은 기본 Role(역할 그룹)에 할당된 타입 post
에 관한 권한 설정과 같습니다. 이때, 10번 줄 create_posts
capability false
설정으로 formfeed
포스트를 워드프레스 기본 시스템에서 추가하는 것을 제한하였습니다.
워드프레스 기본 포스트(콘텐츠) 등록 시스템은 이 포스트처럼 사용자가 특정 애플리케이션(폼)을 작성하여 등록하는 것이 아닌 관리페이지에서 등록하는 포스트나 분류 등의 말 그대로 기본으로 제공하는 인터페이스를 통한 등록을 말합니다.
폼 데이터에서 생성하는 formfeed
포스트는 비공개 포스트 기준을 두었으므로 14, 18, 35번 줄 등에서 적절하게 정의하였습니다. 특별히 25번 줄은 주의해야 하는데, 예를 들어 14번 줄이 false
라면 자동으로 false
적용이 되는 항목들이 있어 따로 정의하지 않아도 되지만, 25번 줄은 영향이 없으므로 꼭 false
로 지정해야 합니다.
25번 줄은 WP REST API 포함(공개)을 결정하는 것으로 워드프레스는 이 포스트 작성일 기준에서 모든 타입의 포스트가 기본 공개로 설정되어 있습니다. 따로 REST API 설정을 변경하지 않았다면 폼 데이터를 비공개로 설정하기 위해서 false
설정을 잊지 않아야 합니다.
이 포스트 작성일 기준에서 정식 도입 상태는 아니지만, 워드프레스 5 버전에서 도입 예정된 Gutenberg 시스템을 비활성화하는 하나의 방법에 25번 설정을
false
로 두는 것도 있습니다.
폼 데이터 포스트 및 시리얼 데이터
위의 코드로 커스텀 포스트 타입을 정의하면 관리페이지에서 ‘문의’라는 메뉴가 나타납니다. 사이트의 폼에서 필드에 데이터를 입력하고 보내기 버튼을 클릭하면 메일로 폼 데이터가 전송되고, 관리페이지 문의 메뉴를 클릭하면 다음 그림의 폼 데이터 포스트를 확인할 수 있습니다. 그림은 화면 옵션(Screen Options)에서 Date(일자) 항목을 해제한 것입니다.
제목을 클릭하면 다음 그림처럼 편집 화면에서 시리얼 형태의 데이터를 볼 수 있습니다.
그림에서 보는 데이터는 워드프레스 포스트 등록 시스템에서 등록한 것이 아니라 직접 구성한 폼에서 시리얼 데이터로 추가(insert)한 것입니다. Visual 모드에서 업데이트 버튼을 클릭하거나 Text 모드에서 편집 후 업데이트하면 데이터 유형이 변하여 이 포스트에서 원하는 결과를 얻을 수 없습니다.
워드프레스 시스템에서 등록하지 않은 데이터는 끝까지 주의해서 처리해야 하는데, 사용자의 실수를 막는 데 필요한 최소한의 방법을 이어서 구성합니다.
워드프레스 포스트 리스트 테이블
이 포스트에서 구성하는 관리페이지 문의(formfeed
) 포스트 목록의 최종 화면은 다음 그림과 같습니다.
포스트 리스트 테이블 열의 이름과 열에 해당하는 데이터를 그림처럼 구성하고, 제목에 링크를 제거하여 편집 화면 접근 경로를 제거합니다. 모든 폼 데이터는 목록에서 열람하는 것을 기준으로 정합니다.
포스트 리스트 테이블 열 이름(header)과 데이터 편집 훅
워드프레스에서 관리페이지 워드프레스 제공 훅을 사용한 포스트 목록 테이블 열 이름과 출력 데이터를 정의하는 방법으로 크게 다음 2, 3번 줄의 2가지를 생각할 수 있습니다. 또, 특정 열에 해당하는 데이터는 6번 줄 훅으로 정의할 수 있습니다.
// 특정 포스트 타입 또는 페이지의 열 이름
manage_{$this->screen->id}_columns
manage_{$post_type}_posts_columns
// 특정 포스트 타입의 열 데이터
manage_{$post_type}_posts_custom_column
이 포스트에서는 3, 6번 줄의 훅을 사용합니다.
열 이름
다음 코드를 플러그인 파일 맨 아래에 그대로 추가하고 저장합니다.
// column name
add_filter( 'manage_formfeed_posts_columns', 'set_formfeed_columns' );
function set_formfeed_columns( $columns ) {
$columns = array(
'cb' => $columns['cb'],
'subject' => '제목',
'name' => '발신자',
'message' => '내용'
);
return $columns;
}
위의 코드에서 $columns
변수에 기본 제공 열을 포함하여 배열로 정의해야 순서 변경도 쉽고, 추가하지 않으면 출력되지 않으므로 제거 또한 쉽습니다. 결과 확인은 미루고 열 데이터를 추가합니다.
열 데이터
다음 코드를 플러그인 파일 맨 아래에 이어서 추가하고 저장합니다.
// column data
add_filter( 'manage_formfeed_posts_custom_column', 'new_modify_formfeed_table_row', 10, 2 );
function new_modify_formfeed_table_row( $column, $post_id ) {
$post = get_post( $post_id );
$post_content = maybe_unserialize( $post->post_content );
// $post_content = maybe_unserialize( get_post_field( 'post_content', $post_id ) );
switch ( $column ) {
case 'subject' :
echo $post_content['제목'];
break;
case 'name' :
$sender = array(
$post_content['이름'],
$post_content['메일'],
$post_content['아이피'],
$post_content['시각'],
$post_content['페이지'],
$post_content['그룹']
);
echo implode( "<br />", $sender );
break;
case 'message' :
echo wpautop( $post_content['내용'] );
break;
}
}
위의 코드 5번 줄에서 maybe_unserialize
함수를 사용하여 시리얼 데이터로 저장한 데이터를 다시 사용할 수 있도록 정의하였습니다.
지금 과정으로 관리페이지 문의 포스트 목록을 확인하면 다음 그림과 같습니다.
post_row_actions
위 그림을 보면 제목 밑에 편집 링크 등이 나옵니다. 이제는 워드프레스 시스템에서 시리얼 데이터 편집의 사용자 실수를 막아 폼 데이터를 목록에서 열람하는 데 오류가 없도록 편집 화면 접근 경로를 제거합니다. 휴지통(Trash)만 남깁니다. 다음 코드를 계속 이어서 추가합니다.
// formfeed
add_filter( 'post_row_actions', 'formfeed_remove_row_actions', 10, 2 );
function formfeed_remove_row_actions( $actions, $type ) {
if( $type->post_type == 'formfeed' ) {
unset( $actions['edit'] );
unset( $actions['view'] );
// unset( $actions['trash'] );
unset( $actions['inline hide-if-no-js'] );
}
return $actions;
}
열 너비 수정
결과는 따로 확인하지 않고, 이어서 포스트 목록 테이블의 각 열 너비를 수정합니다. 다음 코드를 계속 이어서 추가합니다.
// column 너비
add_action( 'admin_head', 'formfeed_admin_head' );
function formfeed_admin_head() {
$screen = get_current_screen();
if ( is_admin() && 'edit-formfeed' == $screen->id ) { ?>
<style type="text/css"> .column-message { width: 50%; } .column-title {width:30%} </style>
<?php
}
}
관리페이지 문의 포스트 목록을 새로 고치면 열 너비의 변화를 볼 수 있습니다.
정리
폼 데이터를 커스텀 포스트 타입의 포스트 데이터로 저장하는 내용은 지금 정도의 내용이면 됩니다. 전체 코드는 간단한 플러그인 형식의 파일로 다음 페이지에서 받을 수 있습니다.
포스트에서는 하나의 파일에 커스텀 포스트 타입, Shortcode, 나머지 액션 등을 모두 추가하여 간단한 플러그인 형식으로 만들었는데, 자신의 사용 방식으로 변경하여 사용하면 됩니다.
폼 데이터를 저장할 때 워드프레스 데이터베이스 테이블의 포스트 콘텐츠로 저장하여 워드프레스 시스템 내부에 포함하는 것이 새로운 테이블을 만들어 저장하는 방법보다 좋지 않을까 생각합니다.
폼 데이터를 저장하는 것은 간단하지만, 데이터 저장을 위한 커스텀 포스트 타입 정의와 설정, 포스트 목록 제어 등 나머지 요소가 더 많은 작업을 요구합니다. 어쩔 수 없으며, 포스트 타입과 분류, 메타 데이터, 권한 정도는 직접 템플릿을 편집하여 워드프레스 사용을 즐기는 사용자라면 한 번은 학습해야 합니다.