목차

Settings API

크게 4분야로 나누어져 있다.

  1. 세팅 등록/해제
  2. 필드, 섹션
  3. 폼 렌더링
  4. 에러

요약 정리한 그림.

wp_settings_api.pdf

세팅 등록/해제

wp_options 테이블에 값을 넣기 위한 작업과 관련 깊다.

register_settings

register_setting 함수는 세팅 항목을 시스템에 등록하는 일을 맡는다.

register_setting( $option_group, $option_name, $sanitize_callback )
unregister_setting( $option_group, $option_name, $sanitize_callback )

MVC 패턴 관점에서 설명하자면 세팅의 <모델>을 정의하는 작업이라고 보면 된다.

필드와 섹션

add_settings_field( $id, $title, $callback, $page, $section, $args )
add_settings_section( $id, $title, $callback, $page )

MVC 패턴 관점에서 바라보면 이 두 함수는 <컨트롤>의 역할을 맡는다. 어떤 HTML구조가 지정된 세팅을 담당하는지를 정의해 주기 때문이다.

폼 렌더링

폼 렌더링을 하기 위해서 프로그래머는 우선 form 태그를 명시적으로 정의해야 한다. 아래는 그 예시이다.

<form method="POST" action="options.php">
<?php settings_fields( 'my-page' );	//pass slug name of page, also referred
                                        //to in Settings API as option group name
do_settings_sections( 'my-page' ); 	//pass slug name of page
submit_button();
?>
</form>
settings_fields( $option_group )

이 함수는 <컨트롤>과 관련이 있다. form 내부의 부가적인 컨트롤, 즉 워드프레스가 부가적으로 사용할 html 태그를 삽입하는 함수이다. 그러므로 반드시 form 태그 안쪽에서 불려야 한다.

do_settings_sections( $page )
do_settings_fields( $page, $section )

이 두 함수는 MVC 패턴에서 <뷰>를 담당한다. 직접적으로 컨트롤들을 화면에 그려 내는 역할을 맡는다.

에러

add_settings_error( $setting, $code, $message, $type )  
get_settings_errors( $setting, $sanitize )  
settings_errors( $setting, $sanitize, $hide_on_update )

예제 코드

다음은 아주 간단하게 세팅 API의 예제를 작성한 것이다. 위 장황한 설명보다 더욱 도움이 되리라 생각한다.

hand-written-settings-sample.php
<?php
/**
Plugin Name: My Settings
Version: 1.0
Author: changwoo
Author URI: mailto://ep6tri@hotmail.com
License: GPL2 or later
*/
 
/**
 * 메뉴 집어넣는 코드
 */
add_action( 'admin_menu', 'my_settings_admin_menu' );
function my_settings_admin_menu() {
 
    add_submenu_page(
        'options-general.php',
        'my settings', // html <title> ... </title> 에 표시될 텍스트
        'my settings', // admin menu 에 표시될 텍스트
        'manage_options', // 권한.
        //
        // page slug.
        // add_settings_section(), add_settings_fields(), do_settings_sections() 의 page 인자로 쓰임.
        'my_settings',
        'my_settings_output_settings'
    );
}
 
/**
 * 메뉴 집어넣는 코드 콜백
 */
function my_settings_output_settings() { ?>
 
    <form method="post" action="<?php echo admin_url( 'options.php' ); ?>" >
 
        <?php
        // register_setting() 의 option_group 인자.
        // 이 함수는 몇몇 hidden field 를 생성하는데, 이 중 하나는 name=option_page, value={$option_group} 인 필드이다.
        // 그러므로 한 번에 submission 되는 form field 는 모두 같은 option group 이어야 제대로 처리된다는 뜻이다.
        settings_fields( 'my_settings_group' );
        ?>
 
        <?php
        // do_settings_sections 로 sections, 복수가 쓰인 것에 유의.
        // 그러므로 인자는 섹션의 슬러그가 아닌, 페이지의 슬러그여야 한다.
        do_settings_sections( 'my_settings' );
        ?>
 
        <?php
        // 이건 뭐 그냥 템플릿 펑션.
        submit_button();
        ?>
    </form>
 
<?php }
 
 
/**
 * 필드 정의 부분.
 */
add_action( 'admin_init', 'my_settings_register_settings' );
 
/**
 * 필드 정의 부분 콜백
 */
function my_settings_register_settings() {
 
    // 옵션 그룹이란, 한 폼에 submission 되는 필드의 단위이다.
    // 워드프레스는 폼이 submission 될 때 POST 값에서 그룹이 미리 등록되었는지를 체크한다.
    // register_setting 에서 두번째 인자는 옵션 값이다.
    // 세 번째는 sanitization 콜백 함수. 문자열이라 오해하지 말 것.
    register_setting( 'my_settings_group', 'my_settings_a01', 'sanitize_text_field' );
    register_setting( 'my_settings_group', 'my_settings_a02', 'sanitize_text_field' );
    register_setting( 'my_settings_group', 'my_settings_a03', 'sanitize_text_field' );
    register_setting( 'my_settings_group', 'my_settings_a04', 'sanitize_text_field' );
 
    register_setting( 'my_settings_group', 'my_settings_b01', 'sanitize_text_field' );
    register_setting( 'my_settings_group', 'my_settings_b02', 'sanitize_text_field' );
    register_setting( 'my_settings_group', 'my_settings_b03', 'sanitize_text_field' );
    register_setting( 'my_settings_group', 'my_settings_b04', 'my_settings_custom_sanitize' );
 
    // 하나의 옵션에 여러 값을 집어 넣는 테크닉이다. PHP 의 serialization 을 이용한다.
    register_setting( 'my_settings_group', 'my_settings_c' );
}
 
 
// 섹션과 필드 설정
add_action( 'admin_init', 'my_settings_sections_fields' );
function my_settings_sections_fields() {
 
    // 섹션 A
    add_settings_section( 'group_a', 'Group A', '', 'my_settings' );
 
    add_settings_field(
        // id 파라미터이지만, 이것이 HTML 요소에서의 id 속성과 반드시 연관되어야만 하지는 않다.
        'a01',
        'A01',
        'my_settings_common',
        'my_settings',
        'group_a', array( 'id' => 'a01' )
    );
 
    add_settings_field( 'a02', 'A02', 'my_settings_common', 'my_settings', 'group_a', array( 'id' => 'a02' ) );
    add_settings_field( 'a03', 'A03', 'my_settings_common', 'my_settings', 'group_a', array( 'id' => 'a03' ) );
    add_settings_field( 'a04', 'A04', 'my_settings_common', 'my_settings', 'group_a', array( 'id' => 'a04' ) );
 
    // 섹션 B
    add_settings_section( 'group_b', 'Group B', '', 'my_settings' );
 
    add_settings_field( 'b01', 'B01', 'my_settings_common', 'my_settings', 'group_b', array( 'id' => 'b01' ) );
    add_settings_field( 'b02', 'B02', 'my_settings_common', 'my_settings', 'group_b', array( 'id' => 'b02' ) );
    add_settings_field( 'b03', 'B03', 'my_settings_common', 'my_settings', 'group_b', array( 'id' => 'b03' ));
    add_settings_field( 'b04', 'B04', 'my_settings_common', 'my_settings', 'group_b', array( 'id' => 'b04' ));
 
    // 섹션 C
    add_settings_section( 'group_c', 'Group C', '', 'my_settings' );
 
    // 한 옵션 키에 여러 값을 저장하기
    add_settings_field( 'c01', 'C01', 'my_settings_serialized', 'my_settings', 'group_c', array( 'id' => 'c', 'key' => 'x' ) );
    add_settings_field( 'c02', 'C02', 'my_settings_serialized', 'my_settings', 'group_c', array( 'id' => 'c', 'key' => 'y' ) );
    add_settings_field( 'c03', 'C03', 'my_settings_serialized', 'my_settings', 'group_c', array( 'id' => 'c', 'key' => 'z' ));
    add_settings_field( 'c04', 'C04', 'my_settings_serialized', 'my_settings', 'group_c', array( 'id' => 'c', 'key' => 'w' ) );
}
 
/** html 콜백 펑션 */
function my_settings_common( $args ) {
 
    $id    = esc_attr( $args['id'] );
    $value = esc_attr( get_option( 'my_settings_' . $args['id'] ) );
 
    printf( '<input type="text" id="my_settings_%1$s" name="my_settings_%1$s" value="%2$s" />', $id, $value );
}
 
/** html 콜백 펑션 */
function my_settings_serialized( $args ) {
 
    $id    = esc_attr( $args['id'] . "[{$args['key']}]" );
    $opt   = get_option( 'my_settings_' . $args['id'] );
    $value = isset( $opt[ $args['key'] ] ) ? esc_attr( $opt[ $args['key'] ] ) : '';
 
    printf( '<input type="text" id="my_settings_%1$s" name="my_settings_%1$s" value="%2$s" />', $id, $value );
}
 
// 옵션 값의 validation 처리
// 어이없게도 아직 settings API 에는 제대로 된 validation 이 없고 일단 sanitize 만 되면 옵션 값은 모두 DB 로 돌진한다.
// 그러므로 만약 옵션 값이 자연수 100 이하의 값만 요구한다 하더라도, 이를 잘 구별할 방법 자체가 존재하지 않는다.
// 그러므로 다음과 같은 우회 방법들을 적절히 찾는 것이 좋다.
//
// 1. 모든 옵션 값들은 디폴트 값을 갖게 하라.
// 2. sanitization 단계에서 validation 을 수행한다. validation 이 fail 하면 settings error 를 띄우고,
//    입력된 값을 세팅 디폴트로 수정한다.
// 3. 사실상 값이 무시된 것으로 간주할 수 있다.
 
function my_settings_custom_sanitize( $value ) {
 
    $default = '50';
 
    $v = (int)$value;
    if( ctype_digit( strval( $value ) ) && 0 < $value && $value < 101 ) {
 
        return $value;
    }
 
    add_settings_error( 'my_settings_group', 'error', 'B04 세팅은 1에서 100까지 정수만 가능합니다.' );
 
    return $default;
}