WordPressテーマやプラグインの設定ページを作成#2

WordPressテーマやプラグインの設定ページを作成#1の続きです。

ここでは保存するオプションデータの検証方法と各種フォームの設置方法を説明します。

データ検証

テキストフィールドやテキストエリアを使ってオプションデータを保存する際に、そのデータを検証することができます。register_setting()の第3引数に検証処理を実装したコールバック関数を設定します。コールバック関数の例は以下です。
【サンプル】

/**
* Validation setting field as needed
*/
function validation( $input )
{
  if( 10 < strlen( $input ) ) {
    add_settings_error(
      'other_option_group',
      'length-not-required',
      'Text must input within 10 characters.'
    );
  }

  return $input;
}

例ではテキストフィールドに入力した文字列が10文字を超えればエラーを表示しています。エラー表示はadd_settings_error()を使います。第1引数にregister_setting()で設定したグループ名を設定します。第2引数にエラー文がHTML出力するid属性に含まれる文字列を設定します。これはなんでもいいです。第3引数に表示するエラー文を設定します。第4引数は初期値が’error’なので設定不要です。

保存するオプションデータのいろんなチェックをコールバック関数に記述すればいいでしょう。

各種オプションフォーム

いろいろな設定をするのに設定の内容に合わせて各種フォームを使用します。ここで説明するフォームは以下です。
・テキストフィールド
・テキストエリア
・チェックボックス(単体・複数)
・ラジオボタン
・セレクトボックス
これらのフォームを使えばほぼ設定したい内容を提供できるのではないかと思います。これら以外にも例えばwysiwygエディタや画像設定フォーム、またはjQueryを使ってタブ画面などの作成もできるかと思いますが興味があればカスタマイズしてみてください。
全てのフォームに共通して必要な設定として、name属性に必ずregister_setting()で設定したオプション名を設定してください。WordPress公式ページにある関数リファレンスにはadd_settings_field()の第1引数で設定するid属性の値をフォームのname属性とid属性に設定するように書いていますが、動作を見たところname属性とid属性は同じである必要ななく、name属性にオプション名が設定されていれば動作するのでそれほど気にする必要なないかと思います。

テキストフィールド

最も使用することが多いフォームかと思います。id属性とname属性にはオプション名を設定しています。value属性にはオプションの値を設定します。
【サンプル】

/**
 * Option set by Text Field
 */
register_setting(
  'my_option_group', // Option group
  'textfield_opt_name' // Option name
);
add_settings_field(
  'textfield_opt_name',
  'TextField',
  'textfield_callback',
  'my-setting-admin',
  'setting_section_id'
);
/**
 * Get the settings option and print its values (Text Field)
 */
function textfield_callback()
{
  $option = get_option( 'textfield_opt_name' );
  printf(
    '<input type="text" id="textfield_opt_name" name="textfield_opt_name" value="%s" class="regular-text" />',
    isset( $option ) ? esc_attr( $option ) : ''
  );
}

 テキストエリア

こちらも使用頻度は多いかと思います。id属性とname属性にはオプション名を設定しています。
【サンプル】

/**
 * Option set by Text Area
 */
register_setting(
  'my_option_group', // Option group
  'textarea_opt_name' // Option name
);
add_settings_field(
  'textarea_opt_name',
  'TextArea',
  'textarea_callback',
  'my-setting-admin',
  'setting_section_id'
);
/**
 * Get the settings option and print its values (Text Area)
 */
function textarea_callback()
{
  $option = get_option( 'textarea_opt_name' );
  printf(
    '<textarea id="textarea_opt_name" name="textarea_opt_name" class="regular-text">%s</textarea>',
    isset( $option ) ? esc_attr( $option ) : ''
  );
}

テキストエリアには複数行を入力すると思いますが、このままHTMLに出力しても改行されません。この場合はnl2br()を使えば自動で改行部分に<br>を入れてくれます。

 チェックボックス(単体)

単体で設定するサンプルです。id属性とname属性にはオプション名を設定しています。単体なのでONかOFF(’1’か’0’)の設定となるので、value属性には’1’を設定しています。checked属性はchecked()関数を使って、オプションの値が’1’なら属性を記述するようにしています。
【サンプル】

/**
 * Option set by Check Box
 */
register_setting(
  'my_option_group', // Option group
  'checkbox_opt_name' // Option name
);
add_settings_field(
  'checkbox_opt_name',
  'CheckBox',
  'checkbox_callback',
  'my-setting-admin',
  'setting_section_id'
);
/**
 * Get the settings option and print its values (Check Box)
 */
function checkbox_callback()
{
  $option = get_option( 'checkbox_opt_name' );
  echo '<input type="checkbox" id="checkbox_opt_name" name="checkbox_opt_name" value="1" ' . checked( 1, $option, false ) . ' /> Description text';
}

 チェックボックス(複数)

複数に設定するサンプルです。こちらは複数の情報が設定されるため、オプションの値が配列になるようにしています。このため他と違って処理が少し複雑です。オプション値を配列にするためname属性には「name=“オプション名[インデックス]」を設定します。ここで設定する配列はコールバック関数呼び出しの引数として渡します。なので、先のadd_settings_field()の第5引数にこの配列を設定します。この配列がそれぞれのチェックボックスの値となります。オプションの値としては、チェックボックスがONの値だけが配列で保存されます。なので、checked属性を記述するかどうかはオプション値の配列に値があればchecked属性を記述する処理をしています。チェックボックスのラベル名はlabelタグを使って表示しています。id属性は例では配列のインデックスを設定していますが、他と同じくオプション名でも動作します。
【サンプル】

/**
 * Option set by Multiple Check Boxes
 */
register_setting(
  'my_option_group', // Option group
  'checkboxes_opt_name' // Option name
);
add_settings_field(
  'checkboxes_opt_name',
  'Multiple CheckBox',
  'checkboxes_callback',
  'my-setting-admin',
  'setting_section_id',
  array(
    'options' => array(
      'wine' => 'Wine',
      'beer' => 'Beer',
      'wisky' => 'Wisky'
    )
  )
);
/**
 * Get the settings option and print its values (Multi Check Box)
 */
function checkboxes_callback( $args )
{
  $optname = 'checkboxes_opt_name';
  $option = get_option( $optname );
  $html = '';
  foreach ( $args['options'] as $val => $title ) {
    if (isset($option) && is_array($option)) {
      $checked = in_array($val, $option) ? 'checked="checked"' : '';
      $html .= sprintf( '<input type="checkbox" id="%2$s" name="%1$s[%2$s]" value="%2$s" %3$s />', $optname, $val, $checked );
    } else {
      $html .= sprintf( '<input type="checkbox" id="%2$s" name="%1$s[%2$s]" value="%2$s" />', $optname, $val );
    }
    $html .= sprintf( '<label for="%1$s[%2$s]"> %3$s</label><br />', $optname, $val, $title );
  }

  $html .= sprintf( '<span class="description"> %s</label>', 'Description text' );

  echo $html;
}

ラジオボタン

ラジオボタンはオプション値は1つですが、選択項目が複数あるので、チェックボックス(複数)と同じくコールバック関数の引数に配列を渡します。ラジオボタンは配列の要素数だけ表示されます。オプション値は1つなので、checked()関数で配列の値をチェックしオプション値と同じならchecked属性を記述する処理をしています。チェックボックスのラベル名はlabelタグを使って表示しています。id属性とname属性にはオプション名を設定しています。
【サンプル】

/**
 * Option set by Radio Buttons
 */
register_setting(
  'my_option_group', // Option group
  'radio_opt_name' // Option name
);
add_settings_field(
  'radio_opt_name',
  'Radio Buttons',
  'radio_callback',
  'my-setting-admin',
  'setting_section_id',
  array(
    'options' => array(
      'beef' => 'Beef',
      'poke' => 'Poke',
      'chicken' => 'Chicken',
      'fish' => 'Fish'
    )
  )
);
/**
 * Get the settings option and print its values (Radio Buttons)
 */
function radio_callback( $args )
{
  $optname = 'radio_opt_name';
  $option = get_option( $optname );
  foreach ( $args['options'] as $val => $title ) {
    printf(
      '<input type="radio" id="%1$s" name="%1$s" value="%2$s" %3$s />', $optname, $val,
checked( $val, $option, false )
    );
    printf( '<label for="%1$s[%2$s]"> %3$s</label><br />', $optname, $val, $title );
  }

  printf( '<span class="description"> %s</label>', 'Description text' );
}

セレクトボックス

セレクトボックスもラジオボタンと同じくオプション値は1つですが、選択項目が複数あるので、コールバック関数の引数に配列を渡します。セレクトボックスの選択要素は配列の数だけ表示されます。オプション値は1つなので、selected()関数で配列の値をチェックしオプション値と同じならselected属性を記述しています。id属性とname属性にはオプション名を設定しています。
【サンプル】

/**
 * Option set by Select Box
 */
register_setting(
  'my_option_group', // Option group
  'selectbox_opt_name' // Option name
);
add_settings_field(
  'selectbox_opt_name',
  'SelectBox',
  array( $this, 'selectbox_callback' ),
  'my-setting-admin',
  'setting_section_id',
  array(
    'options' => array(
      'blue' => 'Blue',
      'red' => 'Red',
      'black' => 'Black'
    )
  )
);
/**
 * Get the settings option and print its values (Select Box)
 */
function selectbox_callback( $args )
{
  $option = get_option( 'selectbox_opt_name' );
  print '<select name="selectbox_opt_name" id="selectbox_opt_name">';

  foreach ( $args['options'] as $val => $title )
    printf(
      '<option value="%1$s" %2$s>%3$s</option>',
      $val,
      selected( $val, $option, false ),
      $title
    );

  print '</select>';
}

 1つのオプション値で複数のフォームデータの扱い方

これまでは1つのフォームに1つのオプション値を設定していましたが、1つのオプション値に複数のフォームから取得するデータを配列で保存することもできます。この場合はそれぞれのフォームのname属性に同じオプション名を設定します。
【サンプル】
<?php
class MySettingsPage
{
    /**
     * Holds the values to be used in the fields callbacks
     */
    private $options;

    /**
     * Start up
     */
    public function __construct()
    {
        add_action( 'admin_menu', array( $this, 'add_plugin_page' ) );
        add_action( 'admin_init', array( $this, 'page_init' ) );
    }
   /**
     * Register and add settings
     */
    public function page_init()
    {        
        register_setting(
            'my_option_group', // Option group
            'my_option_name', // Option name
            array( $this, 'sanitize' ) // Sanitize
        );

        add_settings_field(
            'id_number', // ID
            'ID Number', // Title 
            array( $this, 'id_number_callback' ), // Callback
            'my-setting-admin', // Page
            'setting_section_id' // Section           
        );      

        add_settings_field(
            'title', 
            'Title', 
            array( $this, 'title_callback' ), 
            'my-setting-admin', 
            'setting_section_id'
        );      
    }
    /** 
     * Get the settings option array and print one of its values
     */
    public function id_number_callback()
    {
        printf(
            '<input type="text" id="id_number" name="my_option_name[id_number]" value="%s" />',
            isset( $this->options['id_number'] ) ? esc_attr( $this->options['id_number']) : ''
        );
    }

    /** 
     * Get the settings option array and print one of its values
     */
    public function title_callback()
    {
        printf(
            '<input type="text" id="title" name="my_option_name[title]" value="%s" />',
            isset( $this->options['title'] ) ? esc_attr( $this->options['title']) : ''
        );
    }
}

まとめ

以下にサンプルの全体を掲載します。処理をカプセル化するためクラスにしています。

<?php
/**
 * The Example for control settings page
 */
class MySettingsPage
{
    /**
     * Holds the values to be used in the fields callbacks
     */
    private $options;
	private $option2;
	private $option3;
	private $option4;
	private $option5;
	private $option6;
	private $option7;
	private $option8;

    /**
     * Start up
     */
    public function __construct()
    {
        add_action( 'admin_menu', array( $this, 'add_setting_page' ) );
        add_action( 'admin_init', array( $this, 'page_init' ) );
    }

    /**
     * Add options page
     */
    public function add_setting_page()
    {
        // This page will be under "Settings"
        	add_options_page(
            'Settings Admin',
            'My Settings',
            'manage_options',
            'my-setting-admin',
            array( $this, 'create_admin_page' )
        );
    }

    /**
     * Options page callback
     */
    public function create_admin_page()
    {
        // Set class property
        $this->options = get_option( 'my_option_name' );
		$this->option2 = get_option( 'textfield_opt_name' );
		$this->option3 = get_option( 'textarea_opt_name' );
		$this->option4 = get_option( 'checkbox_opt_name' );
		$this->option5 = get_option( 'checkboxes_opt_name' );
		$this->option6 = get_option( 'radio_opt_name' );
		$this->option7 = get_option( 'selectbox_opt_name' );
		$this->option8 = get_option( 'other_option_name' );
        ?>
        <div class="wrap">
            <?php screen_icon(); ?>
            <h2>My Settings</h2>
            <form method="post" action="options.php">
            <?php
                // This prints out all hidden setting fields
                settings_fields( 'my_option_group' );
                do_settings_sections( 'my-setting-admin' );
                submit_button();
            ?>
            </form>
        </div>
        <?php
    }

    /**
     * Register and add settings
     */
    public function page_init()
    {
        register_setting(
            'my_option_group', // Option group
            'my_option_name', // Option name
            array( $this, 'sanitize' ) // Sanitize
        );

        add_settings_section(
            'setting_section_id', // ID
            'My Example Settings', // Title
            array( $this, 'print_section_info' ), // Callback
            'my-setting-admin' // Page
        );

		/**
	     * Option set in array
	     */
        add_settings_field(
            'id_number', // ID
            'ID Number', // Title
            array( $this, 'id_number_callback' ), // Callback
            'my-setting-admin', // Page
            'setting_section_id' // Section
        );

        add_settings_field(
            'title',
            'Title',
            array( $this, 'title_callback' ),
            'my-setting-admin',
            'setting_section_id'
        );

		/**
	     * Option set by Text Field
	     */
		register_setting(
            'my_option_group', // Option group
            'textfield_opt_name' // Option name
        );
		add_settings_field(
            'textfield_opt_name',
            'TextField',
            array( $this, 'textfield_callback' ),
            'my-setting-admin',
            'setting_section_id'
        );

		/**
	     * Option set by Text Area
	     */
		register_setting(
            'my_option_group', // Option group
            'textarea_opt_name' // Option name
        );
		add_settings_field(
            'textarea_opt_name',
            'TextArea',
            array( $this, 'textarea_callback' ),
            'my-setting-admin',
            'setting_section_id'
        );

		/**
	     * Option set by Check Box
	     */
		register_setting(
            'my_option_group', // Option group
            'checkbox_opt_name' // Option name
        );
		add_settings_field(
            'checkbox_opt_name',
            'CheckBox',
            array( $this, 'checkbox_callback' ),
            'my-setting-admin',
            'setting_section_id'
        );

		/**
	     * Option set by Multiple Check Boxes
	     */
		register_setting(
            'my_option_group', // Option group
            'checkboxes_opt_name' // Option name
        );
		add_settings_field(
            'checkboxes_opt_name',
            'Multiple CheckBox',
            array( $this, 'checkboxes_callback' ),
            'my-setting-admin',
            'setting_section_id',
			array(
				'options'	=> array(
					'wine'	=> 'Wine',
					'beer'	=> 'Beer',
					'wisky'	=> 'Wisky'
				)
			)
        );

		/**
	     * Option set by Radio Buttons
	     */
		register_setting(
            'my_option_group', // Option group
            'radio_opt_name' // Option name
        );
		add_settings_field(
            'radio_opt_name',
            'Radio Buttons',
            array( $this, 'radio_callback' ),
            'my-setting-admin',
            'setting_section_id',
			array(
				'options'	=> array(
					'beef'	=> 'Beef',
					'poke'	=> 'Poke',
					'chicken'	=> 'Chicken',
					'fish'	=> 'Fish'
				)
			)
        );

		/**
	     * Option set by Select Box
	     */
		register_setting(
            'my_option_group', // Option group
            'selectbox_opt_name' // Option name
        );
		add_settings_field(
            'selectbox_opt_name',
            'SelectBox',
            array( $this, 'selectbox_callback' ),
            'my-setting-admin',
            'setting_section_id',
			array(
				'options'     => array(
					'blue'  => 'Blue',
					'red'   => 'Red',
					'black' => 'Black'
				)
			)
        );

		/**
	     * The text validation sample
	     */
		register_setting(
            'my_option_group', // Option group
            'other_option_name', // Option name
            array( $this, 'validation' ) // Sanitize
        );

        add_settings_section(
            'other_section_id', // ID
            'Other Example Settings', // Title
            array( $this, 'print_other_info' ), // Callback
            'my-setting-admin' // Page
        );

        add_settings_field(
            'other_option_name', // ID
            'Text Validation', // Title
            array( $this, 'other_callback' ), // Callback
            'my-setting-admin', // Page
            'other_section_id' // Section
        );
    }

    /**
     * Sanitize each setting field as needed
     *
     * @param array $input Contains all settings fields as array keys
     */
    public function sanitize( $input )
    {
        $new_input = array();

		if( $input['id_number'] != NULL )
			$new_input['id_number'] = absint( $input['id_number'] );

        if( isset( $input['title'] ) )
            $new_input['title'] = sanitize_text_field( $input['title'] );

        return $new_input;
    }

	/**
     * Validation setting field as needed
     */
    public function validation( $input )
    {
        if( 10 < strlen( $input ) ) {
			add_settings_error(
				'other_option_group',
				'length-not-required',
				'Text must input within 10 characters.'
			);
		}

        return $input;
    }

    /**
     * Print the Section text
     */
    public function print_section_info()
    {
        print 'Enter your settings below:';
    }

	/**
     * Print the Section text
     */
    public function print_other_info()
    {
        print 'Validation sample in settings below:';
    }

    /**
     * Get the settings option array and print one of its values
     */
    public function id_number_callback()
    {
        printf(
            '<input type="text" id="id_number" name="my_option_name[id_number]" value="%s"  class="regular-text" />',
            isset( $this->options['id_number'] ) ? esc_attr( $this->options['id_number'] ) : ''
        );
    }

    /**
     * Get the settings option array and print one of its values
     */
    public function title_callback()
    {
        printf(
            '<input type="text" id="title" name="my_option_name[title]" value="%s"  class="regular-text" />',
            isset( $this->options['title'] ) ? esc_attr( $this->options['title'] ) : ''
        );
    }

	/**
     * Get the settings option and print its values (Text Field)
     */
	public function textfield_callback()
    {
        printf(
            '<input type="text" id="textfield_opt_name" name="textfield_opt_name" value="%s" class="regular-text" />',
            isset( $this->option2 ) ? esc_attr( $this->option2 ) : ''
        );
    }

	/**
     * Get the settings option and print its values (Text Area)
     */
	public function textarea_callback()
    {
        printf(
            '<textarea id="textarea_opt_name" name="textarea_opt_name" class="regular-text">%s</textarea>',
            isset( $this->option3 ) ? esc_attr( $this->option3 ) : ''
        );
    }

	/**
     * Get the settings option and print its values (Check Box)
     */
	public function checkbox_callback()
    {
		echo '<input type="checkbox" id="checkbox_opt_name" name="checkbox_opt_name" value="1" ' . checked( 1, $this->option4, false ) . ' /> Description text';
    }

	/**
     * Get the settings option and print its values (Multi Check Box)
     */
	public function checkboxes_callback( $args )
    {
		$optname	= 'checkboxes_opt_name';
		$html		= '';
		foreach ( $args['options'] as $val => $title ) {
			if (isset($this->option5) && is_array($this->option5)) {
				$checked = in_array($val, $this->option5) ? 'checked="checked"' : '';
				$html .= sprintf( '<input type="checkbox" id="%2$s" name="%1$s[%2$s]" value="%2$s" %3$s />', $optname, $val, $checked );
			} else {
				$html .= sprintf( '<input type="checkbox" id="%2$s" name="%1$s[%2$s]" value="%2$s" />', $optname, $val );
			}
			$html .= sprintf( '<label for="%1$s[%2$s]"> %3$s</label><br />', $optname, $val, $title );
		}

		$html .= sprintf( '<span class="description"> %s</label>', 'Description text' );

		echo $html;
    }

	/**
     * Get the settings option and print its values (Radio Buttons)
     */
	public function radio_callback( $args )
	{
		$optname	= 'radio_opt_name';
		foreach ( $args['options'] as $val => $title ) {
			printf(
				'<input type="radio" id="%1$s" name="%1$s" value="%2$s" %3$s />', $optname, $val,
				checked( $val, $this->option6, false )
			);
			printf( '<label for="%1$s[%2$s]"> %3$s</label><br />', $optname, $val, $title );
		}

		printf( '<span class="description"> %s</label>', 'Description text' );
	}

	/**
     * Get the settings option and print its values (Select Box)
     */
	public function selectbox_callback( $args )
	{
		print '<select name="selectbox_opt_name" id="selectbox_opt_name">';

		foreach ( $args['options'] as $val => $title )
			printf(
				'<option value="%1$s" %2$s>%3$s</option>',
				$val,
				selected( $val, $this->option7, false ),
				$title
			);

		print '</select>';
	}

	/**
     * Get the settings option and print its values (Text Field - Other)
     */
	public function other_callback()
    {
        printf(
            '<input type="text" id="other_option_name" name="other_option_name" value="%s" class="regular-text" /><br>',
            isset( $this->option8 ) ? esc_attr( $this->option8 ) : ''
        );
		printf( '<span class="description"> %s</label>', '* Validation text field sample. If you input text over 10 characters, the error message display on the top of page.' );
    }
}

if( is_admin() )
    $my_settings_page = new MySettingsPage();

以上で設定ページの作成は完了です。お疲れ様でした。